Aller au contenu

Programmation PHP avec Symfony/HttpClient

Un livre de Wikilivres.

Composant pour lancer des requêtes HTTP depuis l'application, avec gestion des timeouts, redirections, cache, protocole et en-tête HTTP. Il est configurable en PHP ou dans framework.yaml.

Depuis Symfony 4[1] :

Terminal
Logo
composer require symfony/http-client


Deux solutions :

 HttpClient::create();

ou

 public function __construct(private readonly HttpClientInterface $httpClient)

Par défaut, l'appel statique à la classe HttpClient instancie un CurlHttpClient, alors que l'injection du service via HttpClientInterface récupère un TraceableHttpClient. Ce dernier est préférable puisqu'il affiche toutes les requêtes dans le profiler de Symfony.

On peut forcer l'utilisation de HTTP 2 à la création :

        $httpClient = HttpClient::create(['http_version' => '2.0']);
        $response = $httpClient->request('GET', 'https://fr.wikibooks.org/');
        if (200 == $response->getStatusCode()) {
            dd($response->getContent());
        } else {
            dd($response->getInfo('error'));
        }

Logo

Ce code ne lève pas les exceptions de résolution DNS.

Exemple en POST avec authentification :

        $response = $httpClient->request('POST', 'https://fr.wikibooks.org/w/api.php', [
            'auth_bearer' => 'mon_token',
            'jsonA' => $keyValuePairs,
        ]);

Pour lancer plusieurs appels asynchrones, il suffit de placer leurs $response->getContent() ensemble, après tous les $httpClient->request().

Pour envoyer un fichier il y a plusieurs solutions :

  • Utiliser le type MIME correspondant à son extension (ex : 'application/pdf', 'application/zip'...). Mais on ne peut envoyer que le fichier dans la requête.
  • Utiliser le type MIME 'application/json' et l'encoder en base64. Il peut ainsi être envoyé avec d'autres données.
  • Utiliser le type MIME 'multipart/form-data'[2].

Problèmes connus

[modifier | modifier le wikicode]

Ce composant est relativement jeune et souffre d'incomplétudes.

  • On peut avoir du "null given" à tort sur un mapping DNS, solvable en rajoutant une option :
        $options = array_merge($options, [
            'resolve' => ['localhost' => '127.0.0.1']
        ]);
  • $httpClient->request() renvoie une Symfony\Contracts\HttpClient\ResponseInterface, mais en cas d'erreur, elle ne contient qu'une ligne de résumé, soit moins d'informations qu'un client comme Postman.

Ce composant peut aussi serveur aux tests fonctionnels via PhpUnit. On l'appelle alors avec static::createClient si le test extends WebTestCase. Dans le cas d'un projet API Platform, on l'appelle de la même manière mais le test extends ApiTestCase.

Exemple :

$client = static::createClient();
$client->request('GET', '/home');
var_dump($client->getResponse()->getContent());

Pour simuler plusieurs clients en parallèle : $client->insulate().

Pour simuler un utilisateur : $client->loginUser($monUser).

Logo

Pour un test de bundle, il faut créer une classe Kernel qui charge les routes en plus[3].