Using Guzzle - Web Service

I have been working on a web service to communicate with another server for a client. Guzzle is the client the AWS services use, and in this particular project, this is already installed, so is a natural for the task.

The purpose of this article is to point out a couple of details left out of the guzzle documentation that I would have found helpful.

Overview

Two servers, the first will use Guzzle to send a message to the second, the second will receive the message, do some work and send a reply back to the first which will then receive this answer.

$client->send()

This is the documentation on sending a POST request with a raw body:
$r = $client->post('http://httpbin.org/post', ['body' => 'raw data']);

In many of their examples, the action would not work until you add the ->send() call. Here is a complete example of posting from the first server to the second (this is wrapped in a class, then a function, both not shown here, so the origin of some of the variables will be missing):

require_once ( PATH . "/aws-autoloader.php");  
use Guzzle\Http\Client as GuzzleClient;

$post_data = array('content' => $post_content);

$post_data = array('data'=>json_encode($post_data));

$this->client = new GuzzleClient($post_url);    

$response = $this->client->post('', null, $post_data)->send();

The $post_url is the http URI to the receiving page. Be certain to add the ->send(); call to the end...

Troubleshooting Tip

When initially writing this code, you need to see if the second server is actually receiving the request from the first. For that, I tailed the access log on the second server in putty via ssh:

:~#tail -f /var/log/apache2/access.log

and when the request is made, you will receive a result similar to this:
10.1xx.xxx.xxx - - [24/Mar/2014:09:31:44 -0400] "POST /my_service_name/log/some_log_need HTTP/1.1" 200 657 "-" "Guzzle/3.7.3 curl/7.24.0 PHP/5.3.14"

Receiving the Guzzle Response

The Guzzle documentation suggests receiving the response back from the second server like this:

    $body = $response->getBody();
    echo $body;
    // { "some_json_data" ...}

Unfortunately, when I dump this to the screen using print_r, this is what I get:

Guzzle\Http\EntityBody Object
(
[contentEncoding:protected] => 
[rewindFunction:protected] => 
[stream:protected] => Resource id #57
[size:protected] => 
[cache:protected] => Array
    (
        [wrapper_type] => PHP
        [stream_type] => TEMP
        [mode] => w+b
        [unread_bytes] => 0
        [seekable] => 1
        [uri] => php://temp
        [is_local] => 1
        [is_readable] => 1
        [is_writable] => 1
    )

[customData:protected] => Array
    (
        [default] => 1
    )

)

...and you guessed it, this is not very useful.

The magic nugget which is in their documentation, but seems to be very rare in the examples is that to cast the result to a string, you need to add true to the call:

$body = $response->getBody(TRUE);

echo $body;

// you will now see the reply from the second server: "test reply"

Troubleshooting Tip

Seeing the request hit the second server is one thing, sometines you need to see that that server's reply is actually coming back to the first server. To do that, I again use putty and ssh, and using tcpdump, I throw the network packets to the screen to verify the content that I am receiving:

:~# tcpdump -nnvvXSs 1514 not port 22 and host second-server-domain.com and port 80`

You will see something like this:

0x0270:  2d4c 656e 6774 683a 2034 350d 0a43 6f6e  -Length:.45..Con
    0x0280:  2d54 7970 653a 2074 6578 742f  tent-Type:.text/
    0x0290:  0d0a 0d0a 0937 632f 464d 445a  html.....7c/FMDZ
    0x02a0:  3263 4f69 6f46 7062 3762 5473  ifGp2cOioFpb7bTs
    0x02b0:  4d68 3279 2f6e 7571 5565 686e  dUemMh2y/nuqUehn
    0x02c0:  6f75 626b 3d                             oubk=

The part on the right starting with html.....7c/FMDZ is the content and in this case, I am encrypting it as the server is not using ssl for the connection, so it will not be understandable. If it were not encrypted, you would be able to read "test.data" somewhere in there.

So, being able to see the results of the calls to Guzzle is very useful to get it working. The final line in the example above would be:

$result = $response->getBody(TRUE);
// $result  now shows "test data"