Guzzle 6: plus de méthode json () pour les réponses

172

Précédemment dans Guzzle 5.3:

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

Je pourrais facilement obtenir un tableau PHP à partir d'une réponse JSON. Maintenant, dans Guzzle 6, je ne sais pas comment faire. Il ne semble plus y avoir de json()méthode. J'ai (rapidement) lu le doc de la dernière version et je n'ai rien trouvé sur les réponses JSON. Je pense que j'ai raté quelque chose, peut-être qu'il y a un nouveau concept que je ne comprends pas (ou peut-être que je n'ai pas lu correctement).

Est-ce (ci-dessous) nouveau moyen le seul moyen?

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

Ou y a-t-il une aide ou quelque chose comme ça?

rap-2-h
la source

Réponses:

292

J'utilise json_decode($response->getBody())maintenant au lieu de $response->json().

Je soupçonne que cela pourrait être une victime de la conformité PSR-7.

meriial
la source
4
Rien dans la documentation ne rend cela explicite, mais il semble qu'ils aient progressivement supprimé l' $response->json()aide.
trombone
60
Si vous attendez une réponse de tableau comme celle de l'original ->json(), utilisez json_decode($response->getBody(), true)plutôt pour obtenir un tableau au lieu d'un stdObject
Jay El-Kaake
14
En utilisant strict_types, j'avais besoin de lancer le corps de la réponse Guzzle en chaîne avant de le décoder:json_decode((string) $response->getBody(), true)
Yoan Tournade
J'ai toujours aimé utiliser \GuzzleHttp\json_decode(ou \GuzzleHttp\Utils::jsonDecodeselon la version de Guzzle sur laquelle vous êtes) qui a une signature compatible \json_decode, mais lève une exception en cas d'erreur, en tirant parti d'une gestion correcte des erreurs.
Adrian Föder
112

Vous passez à:

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

Au lieu de l'autre commentaire si vous voulez qu'il fonctionne exactement comme avant afin d'obtenir des tableaux au lieu d'objets.

dmyers
la source
29

J'utilise $response->getBody()->getContents()pour obtenir JSON à partir de la réponse. Guzzle version 6.3.0.

jusep
la source
6
L'appel getContents()dans le corps de la réponse videra le flux et le prochain appel à getContents()retournera vide. Si vous voulez obtenir le corps sous forme de chaîne, utilisez:strval($response->getBody())
JVitela
1
Je souhaite que ce commentaire soit plus élevé. J'enregistrais ma réponse en utilisant getContent et quand je suis allé analyser une ligne plus tard, mon tableau était vide. Ça m'a coûté des heures. Merci!
Colin
14

Si vous êtes toujours intéressé, voici ma solution de contournement basée sur la fonctionnalité middleware Guzzle :

  1. Créez JsonAwaraResponsequi décodera la réponse JSON par Content-Typeen-tête HTTP, sinon - cela agira comme une réponse Guzzle standard:

    <?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. Créez un middleware qui va remplacer les réponses Guzzle PSR-7 par l'implémentation de réponse ci-dessus:

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

Après cela, pour récupérer JSON en tant que tableau natif PHP, utilisez Guzzle comme toujours:

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

Testé avec guzzlehttp / guzzle 6.3.3

Andrew
la source
C'est de bonne qualité. Utilisation dans une tâche de client API Rest que je viens de récupérer au travail. J'ai cependant une question sur votre réponse. Votre classe JsonAwareResponse était-elle destinée à être sous l'espace de noms GuzzleHttp? J'ai fini par créer cette classe sous mon propre espace de noms, mais pendant une seconde, j'ai cherché dans la base de code de GuzzleHttp à la recherche de cette classe. :) Merci encore!
floorz
N'utilisez pas cette solution car elle rompt l'interface PSR-7 MessageInterface. Avec PSR-7, il n'y a pas de solution légale pour patcher cette interface pour renvoyer le JSON décodé à partir de la getBody()méthode.
Sergey Nevmerzhitsky
3

$responseest une instance de PSR-7 ResponseInterface. Pour plus de détails, voir https://www.php-fig.org/psr/psr-7/#3-interfaces

getBody()renvoie StreamInterface:

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

StreamInterfacemet en œuvre __toString()ce qui fait

Lit toutes les données du flux dans une chaîne, du début à la fin.

Par conséquent, pour lire le corps sous forme de chaîne, vous devez le convertir en chaîne:

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


Gotchas

  1. json_decode($response->getBody()n'est pas la meilleure solution car il transforme comme par magie le flux en chaîne pour vous. json_decode()nécessite une chaîne comme 1er argument.
  2. Ne l'utilisez $response->getBody()->getContents()que si vous savez ce que vous faites. Si vous lisez la documentation pour getContents(), il est dit: Returns the remaining contents in a string. Par conséquent, l'appel getContents()lit le reste du flux et l'appel à nouveau ne retourne rien car le flux est déjà à la fin. Vous devrez rembobiner le flux entre ces appels.
simPod
la source
1

L'ajout ->getContents()ne renvoie pas de réponse jSON, mais plutôt sous forme de texte.

Vous pouvez simplement utiliser json_decode

Moh
la source
Il renvoie JSON sous forme de texte, pas de HTML.
František Maša