Guzzlehttp - How get the body of a response from Guzzle 6?

176,155

Solution 1

Guzzle implements PSR-7. That means that it will by default store the body of a message in a Stream that uses PHP temp streams. To retrieve all the data, you can use casting operator:

$contents = (string) $response->getBody();

You can also do it with

$contents = $response->getBody()->getContents();

The difference between the two approaches is that getContents returns the remaining contents, so that a second call returns nothing unless you seek the position of the stream with rewind or seek .

$stream = $response->getBody();
$contents = $stream->getContents(); // returns all the contents
$contents = $stream->getContents(); // empty string
$stream->rewind(); // Seek to the beginning
$contents = $stream->getContents(); // returns all the contents

Instead, usings PHP's string casting operations, it will reads all the data from the stream from the beginning until the end is reached.

$contents = (string) $response->getBody(); // returns all the contents
$contents = (string) $response->getBody(); // returns all the contents

Documentation: http://docs.guzzlephp.org/en/latest/psr7.html#responses

Solution 2

If expecting JSON back, the simplest way to get it:

$data = json_decode($response->getBody()); // returns an object

// OR

$data = json_decode($response->getBody(), true); // returns an array

json_decode() will automatically cast the body to string, so there is no need to call getContents().

Solution 3

For get response in JSON format :

1.

$response = (string) $res->getBody();
$response =json_decode($response); // Using this you can access any key like below
$key_value = $response->key_name; //access key  
$response = json_decode($res->getBody(),true);
$key_value =   $response['key_name'];//access key
Share:
176,155

Related videos on Youtube

Greg
Author by

Greg

jQuery, PHP, Python dev.

Updated on March 25, 2021

Comments

  • Greg
    Greg about 3 years

    I'm trying to write a wrapper around an api my company is developing. It's restful, and using Postman I can send a post request to an endpoint like http://subdomain.dev.myapi.com/api/v1/auth/ with a username and password as POST data and I am given back a token. All works as expected. Now, when I try and do the same from PHP I get back a GuzzleHttp\Psr7\Response object, but can't seem to find the token anywhere inside it as I did with the Postman request.

    The relevant code looks like:

    $client = new Client(['base_uri' => 'http://companysub.dev.myapi.com/']);
    $response = $client->post('api/v1/auth/', [
        'form_params' => [
            'username' => $user,
            'password' => $password
        ]
    ]);
    
    var_dump($response); //or $resonse->getBody(), etc...
    

    The output of the code above looks something like (warning, incoming wall of text):

    object(guzzlehttp\psr7\response)#36 (6) {
      ["reasonphrase":"guzzlehttp\psr7\response":private]=>
      string(2) "ok"
      ["statuscode":"guzzlehttp\psr7\response":private]=>
      int(200)
      ["headers":"guzzlehttp\psr7\response":private]=>
      array(9) {
        ["connection"]=>
        array(1) {
          [0]=>
          string(10) "keep-alive"
        }
        ["server"]=>
        array(1) {
          [0]=>
          string(15) "gunicorn/19.3.0"
        }
        ["date"]=>
        array(1) {
          [0]=>
          string(29) "sat, 30 may 2015 17:22:41 gmt"
        }
        ["transfer-encoding"]=>
        array(1) {
          [0]=>
          string(7) "chunked"
        }
        ["content-type"]=>
        array(1) {
          [0]=>
          string(16) "application/json"
        }
        ["allow"]=>
        array(1) {
          [0]=>
          string(13) "post, options"
        }
        ["x-frame-options"]=>
        array(1) {
          [0]=>
          string(10) "sameorigin"
        }
        ["vary"]=>
        array(1) {
          [0]=>
          string(12) "cookie, host"
        }
        ["via"]=>
        array(1) {
          [0]=>
          string(9) "1.1 vegur"
        }
      }
      ["headerlines":"guzzlehttp\psr7\response":private]=>
      array(9) {
        ["connection"]=>
        array(1) {
          [0]=>
          string(10) "keep-alive"
        }
        ["server"]=>
        array(1) {
          [0]=>
          string(15) "gunicorn/19.3.0"
        }
        ["date"]=>
        array(1) {
          [0]=>
          string(29) "sat, 30 may 2015 17:22:41 gmt"
        }
        ["transfer-encoding"]=>
        array(1) {
          [0]=>
          string(7) "chunked"
        }
        ["content-type"]=>
        array(1) {
          [0]=>
          string(16) "application/json"
        }
        ["allow"]=>
        array(1) {
          [0]=>
          string(13) "post, options"
        }
        ["x-frame-options"]=>
        array(1) {
          [0]=>
          string(10) "sameorigin"
        }
        ["vary"]=>
        array(1) {
          [0]=>
          string(12) "cookie, host"
        }
        ["via"]=>
        array(1) {
          [0]=>
          string(9) "1.1 vegur"
        }
      }
      ["protocol":"guzzlehttp\psr7\response":private]=>
      string(3) "1.1"
      ["stream":"guzzlehttp\psr7\response":private]=>
      object(guzzlehttp\psr7\stream)#27 (7) {
        ["stream":"guzzlehttp\psr7\stream":private]=>
        resource(40) of type (stream)
        ["size":"guzzlehttp\psr7\stream":private]=>
        null
        ["seekable":"guzzlehttp\psr7\stream":private]=>
        bool(true)
        ["readable":"guzzlehttp\psr7\stream":private]=>
        bool(true)
        ["writable":"guzzlehttp\psr7\stream":private]=>
        bool(true)
        ["uri":"guzzlehttp\psr7\stream":private]=>
        string(10) "php://temp"
        ["custommetadata":"guzzlehttp\psr7\stream":private]=>
        array(0) {
        }
      }
    }
    

    The output from Postman was something like:

    {
        "data" : {
            "token" "fasdfasf-asfasdfasdf-sfasfasf"
        }
    }
    

    Clearly I'm missing something about working with the response objects in Guzzle. The Guzzle response indicates a 200 status code on the request, so I'm not sure exactly what I need to do to retrieve the returned data.

    • Federkun
      Federkun almost 9 years
      $response->getBody()->getContents() doesn't work?
  • Maximus
    Maximus over 8 years
    The getContents function is only in one small part of the Guzzle 6 documentation (in the streams section), and I missed it. You saved me from a whole lot of searching.
  • John
    John over 8 years
    THANK YOU. It's unbelievable that this is not more clear in the documentation. Even their official documentation (docs.guzzlephp.org/en/latest) makes it seem like calling $res->getBody() returns what you would normally expect.
  • cwhsu
    cwhsu over 7 years
    They should really put something like a note or notice in the official documents. I wasted two days on this issue.
  • Magnus
    Magnus over 7 years
    +1 The Guzzle documentation falsely states that "you can pass true to this method [getBody()] to retrieve the body as a string.". That doesn't seem to work for me using Guzzle 6, but casting to string or using getContents() does work.
  • Federkun
    Federkun over 7 years
    @BadCash that's the documentation for guzzle3
  • Magnus
    Magnus over 7 years
    @Federkun I see, thanks! However, that's the documentation that ranks at the top of Google when searching for "guzzle getbody string", so I guess I'm not the only one being led astray by it. Especially since the only thing indicating that it's for a specific older version is a "3" in the URL...
  • Sygon
    Sygon over 6 years
    You can also use json_decode. For example wrap your response in json_decode($response, true); this will return an array.
  • Raccoon
    Raccoon almost 6 years
    God... i wastest several hours because of this... thanks
  • Melroy van den Berg
    Melroy van den Berg over 5 years
    You could also take a look at this example, by using middle-ware: stackoverflow.com/questions/30530172/…
  • Akio
    Akio about 5 years
    $response->getBody()->getContents(); returns with a HTTP header in array form. Anyone knows how to fix this? More on this: stackoverflow.com/questions/56004396/…
  • Shardj
    Shardj over 4 years
    Highly recommend you don't use (string) $response->getBody() as it doesn't actually retrieve all data. It retrieves the length of the default, so it could truncate the actual value. github.com/guzzle/guzzle/issues/1610
  • Eric McWinNEr
    Eric McWinNEr over 4 years
    Why isn' this answer getting more attention??? This is precisely what I needed. Thanks @MaskimIvanov
  • Alator
    Alator about 4 years
    That was the most simple and easy thing for me too. Thanks
  • j13k
    j13k over 3 years
    This simple answer 'solves' the immediate problem, but it misses the nuance of the accepted answer by @Federkun. The reason this 'just works' most of the time is because the call to json_decode implicitly casts the response body as a string. Having said that, it is worth understanding the accepted answer, as there can be problems with the string casting approach not always retrieving all data, as highlighted in the comment by @Shardj.
  • Вася Аристов
    Вася Аристов over 3 years
    This method works but it will cause errors during static analysis
  • Maksim Borodov
    Maksim Borodov about 3 years
    @Shardj How can i retrive all content? My content truncating.
  • Shardj
    Shardj about 3 years
    @MaksimBorodov I believe the solution is in the comments of the github issue I linked previously
  • Catto
    Catto over 2 years
    Thanks!! I just missed the true keyword
  • Szczepan Hołyszewski
    Szczepan Hołyszewski about 2 years
    Finding this answer early in my quest saved me hours of hair pulling. One HUGE gotcha: if you have set up request logging using Middleware::log(), and the message formatter uses {res_body} anywhere in the format string, then body WILL have been read by the time you get the response object, and $response->getBody()->getContents() WILL return an empty string even though YOU haven't read the body!