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

3

231

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.

Clerihew answered 30/5, 2015 at 17:29 Comment(1)
$response->getBody()->getContents() doesn't work?Inactivate
I
592

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

Inactivate answered 30/5, 2015 at 17:43 Comment(13)
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.Outbuilding
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.Sufism
They should really put something like a note or notice in the official documents. I wasted two days on this issue.Subterrane
+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.Carcanet
@BadCash that's the documentation for guzzle3Inactivate
@Inactivate 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...Carcanet
You can also use json_decode. For example wrap your response in json_decode($response, true); this will return an array.Hus
You could also take a look at this example, by using middle-ware: #30530672Fossiliferous
$response->getBody()->getContents(); returns with a HTTP header in array form. Anyone knows how to fix this? More on this: #56004896Rufina
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/1610Couperin
@Couperin How can i retrive all content? My content truncating.Carlson
@MaksimBorodov I believe the solution is in the comments of the github issue I linked previouslyCouperin
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!Gujarat
I
68

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().

Italy answered 29/11, 2019 at 15:45 Comment(2)
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.Cullet
This method works but it will cause errors during static analysisRider
A
13

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
Arathorn answered 8/10, 2020 at 12:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.