Guzzle 6: no más método json () para respuestas

172

Anteriormente en Guzzle 5.3:

$response = $client->get('http://httpbin.org/get');
$array = $response->json(); // Yoohoo
var_dump($array[0]['origin']);

Podría obtener fácilmente una matriz PHP a partir de una respuesta JSON. Ahora en Guzzle 6, no sé cómo hacerlo. Parece que ya no hay json()método. Leí (rápidamente) el documento de la última versión y no encontré nada sobre las respuestas JSON. Creo que me perdí algo, tal vez hay un nuevo concepto que no entiendo (o tal vez no lo leí correctamente).

¿Es esta (abajo) nueva forma la única forma?

$response = $client->get('http://httpbin.org/get');
$array = json_decode($response->getBody()->getContents(), true); // :'(
var_dump($array[0]['origin']);

¿O hay un ayudante o algo así?

rap-2-h
fuente

Respuestas:

292

Yo uso json_decode($response->getBody())ahora en lugar de $response->json().

Sospecho que esto podría ser una víctima del cumplimiento de PSR-7.

meriial
fuente
44
No hay nada en la documentación que explique esto, pero parece que han eliminado el $response->json()ayudante.
clip
6060
Si espera una respuesta de matriz como el funcionamiento del original ->json(), use json_decode($response->getBody(), true)en su lugar para obtener una matriz en lugar de un objeto estándar
Jay El-Kaake
14
Utilizando strict_types, necesitaba lanzar el cuerpo de respuesta de Guzzle a la cadena antes de decodificarlo:json_decode((string) $response->getBody(), true)
Yoan Tournade el
Siempre me gustó usar \GuzzleHttp\json_decode(o \GuzzleHttp\Utils::jsonDecodedependiendo de la versión de Guzzle en la que estés) que tiene una firma compatible \json_decode, pero arroja una excepción si hay un error, aprovechando el manejo de errores adecuado.
Adrian Föder
112

Cambias a:

json_decode($response->getBody(), true)

En lugar del otro comentario, si desea que funcione exactamente como antes para obtener matrices en lugar de objetos.

dmyers
fuente
29

Yo uso $response->getBody()->getContents()para obtener JSON de la respuesta. Guzzle versión 6.3.0.

jusep
fuente
66
Llamar getContents()al cuerpo de respuesta vaciará la secuencia y la próxima llamada a getContents()volverá vacía. Si desea obtener el cuerpo como cadena:strval($response->getBody())
JVitela
1
Desearía que este comentario fuera más alto. Estaba registrando mi respuesta usando getContent y cuando fui a analizar una línea más tarde, mi matriz estaba vacía. Me costó horas ¡Gracias!
Colin
14

Si todavía están interesados, aquí está mi solución basada en la función de middleware Guzzle :

  1. Cree JsonAwaraResponseque decodificará la respuesta JSON por Content-Typeencabezado HTTP, si no, actuará como respuesta estándar de Guzzle:

    <?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;
        }
    }
  2. Cree Middleware que reemplazará las respuestas de Guzzle PSR-7 con la implementación de Respuesta anterior:

    <?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');

Después de esto para recuperar JSON como matriz nativa de PHP, use Guzzle como siempre:

$jsonArray = $client->get('http://httpbin.org/headers')->getBody();

Probado con guzzlehttp / guzzle 6.3.3

Andrés
fuente
Estas son algunas cosas buenas. Utilizando una tarea de Rest API Client que acabo de recoger en el trabajo. Sin embargo, tengo una pregunta sobre tu respuesta. ¿Su clase JsonAwareResponse estaba destinada a estar bajo el espacio de nombres GuzzleHttp? Terminé creando esa clase bajo mi propio espacio de nombres, pero por un segundo estuve buscando alrededor de la base de código de GuzzleHttp buscando esa clase. :) ¡Gracias de nuevo!
floorz
No use esta solución porque rompe la interfaz PSR-7 MessageInterface. Con PSR-7 no hay una solución legal para parchear esta interfaz para devolver JSON decodificado del getBody()método.
Sergey Nevmerzhitsky
3

$responsees una instancia de PSR-7 ResponseInterface. Para más detalles ver https://www.php-fig.org/psr/psr-7/#3-interfaces

getBody()devuelve StreamInterface:

/**
 * Gets the body of the message.
 *
 * @return StreamInterface Returns the body as a stream.
 */
public function getBody();

StreamInterfaceimplementa lo __toString()que hace

Lee todos los datos de la secuencia en una cadena, de principio a fin.

Por lo tanto, para leer el cuerpo como una cadena, debe convertirlo en una cadena:

$stringBody = (string) $response->getBody()


Gotchas

  1. json_decode($response->getBody()no es la mejor solución, ya que mágicamente emite secuencia en cadena para ti. json_decode()requiere cadena como primer argumento.
  2. No lo use a $response->getBody()->getContents()menos que sepa lo que está haciendo. Si usted lee la documentación getContents(), que dice: Returns the remaining contents in a string. Por lo tanto, llamar getContents()lee el resto de la secuencia y volver a llamar no devuelve nada porque la secuencia ya está al final. Tendría que rebobinar la secuencia entre esas llamadas.
simPod
fuente
1

Agregar ->getContents()no devuelve la respuesta jSON, sino que se devuelve como texto.

Simplemente puedes usar json_decode

Oficial médico
fuente
Devuelve JSON como texto, no HTML.
František Maša