Guzzle 6: no more json() method for responses
PhpGuzzlePhp Problem Overview
Previously in Guzzle 5.3:
$response = $client->get('http://httpbin.org/get');
$array = $response->json(); // Yoohoo
var_dump($array[0]['origin']);
I could easily get a PHP array from a JSON response. Now In Guzzle 6, I don't know how to do. There seems to be no json()
method anymore. I (quickly) read the doc from the latest version and don't found anything about JSON responses. I think I missed something, maybe there is a new concept that I don't understand (or maybe I did not read correctly).
Is this (below) new way the only way?
$response = $client->get('http://httpbin.org/get');
$array = json_decode($response->getBody()->getContents(), true); // :'(
var_dump($array[0]['origin']);
Or is there an helper or something like that?
Php Solutions
Solution 1 - Php
I use json_decode($response->getBody())
now instead of $response->json()
.
I suspect this might be a casualty of PSR-7 compliance.
Solution 2 - Php
You switch to:
json_decode($response->getBody(), true)
Instead of the other comment if you want it to work exactly as before in order to get arrays instead of objects.
Solution 3 - Php
I use $response->getBody()->getContents()
to get JSON from response.
Guzzle version 6.3.0.
Solution 4 - Php
If you guys still interested, here is my workaround based on Guzzle middleware feature:
-
Create
JsonAwaraResponse
that will decode JSON response byContent-Type
HTTP header, if not - it will act as standard Guzzle Response:<?php namespace GuzzleHttp\Psr7; class JsonAwareResponse extends Response { /** * Cache for performance * @var array */ private $json; public function getBody() { if ($this->json) { return $this->json; } // get parent Body stream $body = parent::getBody(); // if JSON HTTP header detected - then decode if (false !== strpos($this->getHeaderLine('Content-Type'), 'application/json')) { return $this->json = \json_decode($body, true); } return $body; } }
-
Create Middleware which going to replace Guzzle PSR-7 responses with above Response implementation:
<?php $client = new \GuzzleHttp\Client(); /** @var HandlerStack $handler */ $handler = $client->getConfig('handler'); $handler->push(\GuzzleHttp\Middleware::mapResponse(function (\Psr\Http\Message\ResponseInterface $response) { return new \GuzzleHttp\Psr7\JsonAwareResponse( $response->getStatusCode(), $response->getHeaders(), $response->getBody(), $response->getProtocolVersion(), $response->getReasonPhrase() ); }), 'json_decode_middleware');
After this to retrieve JSON as PHP native array use Guzzle as always:
$jsonArray = $client->get('http://httpbin.org/headers')->getBody();
Tested with guzzlehttp/guzzle 6.3.3
Solution 5 - Php
$response
is instance of PSR-7 ResponseInterface
. For more details see https://www.php-fig.org/psr/psr-7/#3-interfaces
getBody()
returns StreamInterface
:
/**
* Gets the body of the message.
*
* @return StreamInterface Returns the body as a stream.
*/
public function getBody();
StreamInterface
implements __toString()
which does
> Reads all data from the stream into a string, from the beginning to end.
Therefore, to read body as string, you have to cast it to string:
$stringBody = (string) $response->getBody()
Gotchas
json_decode($response->getBody()
is not the best solution as it magically casts stream into string for you.json_decode()
requires string as 1st argument.- Don't use
$response->getBody()->getContents()
unless you know what you're doing. If you read documentation forgetContents()
, it says:Returns the remaining contents in a string
. Therefore, callinggetContents()
reads the rest of the stream and calling it again returns nothing because stream is already at the end. You'd have to rewind the stream between those calls.
Solution 6 - Php
Adding ->getContents()
doesn't return jSON response, instead it returns as text.
You can simply use json_decode