Le composant HttpClient de Symfony

HttpClient, Mais pourquoi ?

En première instance, en voyant le titre, on se dit que ça ne sert à rien. Il existe déjà Guzzle, au pire on fait du curl.

Et c'est bien ça le problème. Dès que nous voulons appeler une API externe nous allons utiliser un bundle comme Guzzle. Notre code devient donc dépendant de Guzzle directement ainsi que de ses dépendances.

La PSR-18 "http Client" propose de créer un "contrat" qui va permettre à notre code d'être indépendant de l'implémentation permettant de faire des appels http.

The goal of this PSR is to allow developers to create libraries decoupled from HTTP client implementations. https://www.php-fig.org/psr/psr-18/

httpClient est donc un contrat unique créé dans le but d’implémenter cette Psr18. C’est une interface pour nous, développeurs, permettant de créer une application sans prendre en considération quelle primitive va être utilisée pour réaliser des appels http.

 

Qu’importe le composant primitif que l’on souhaite (curl, native, …) nous allons donc pouvoir coder de la même manière. C’est aussi la possibilité de changer le composant natif en changeant l’implémentation sans changer une seule ligne écrite dans notre application.

Contracts/httpClient

Le contrat en lui même est standalone. Il suit les recommandation psr18.

C’est une interface qui permet de faire des appels simplement (un peu comme guzzle)

80% des cas d’utilisation

 

Les options

Pour l’utilisation d’headers et de body, c’est le troisième paramètre qui nous intéresse : $options

C’est un array associatif avec lequel on peut passer les différentes informations nécessaires.

Les paramètres de requête (query param) peuvent également être passés dans le tableau options :

Encore mieux, le contrat d’interface supporte également de base les bearers et les body en json :

 

La réponse

La réponse possède également des méthodes répondant à la plupart des appels réalisés dans un projet standard :

Elles sont assez explicites. Cependant toArray() permet de convertir une réponse json en array avec une simple méthode. C’est la fin des petites lignes de code supplémentaires permettant de json_decode.

Comment migrer vers httpClient ?

Encore une fois c’est très simple et peu de lignes sont impactées :

 

Une gestion des erreurs

Contrairement à d’autres alternatives, les erreurs sont toutes gérées par le composant qui implémente ce contrat.

On peut également définir le nombre de redirection que l’on souhaite au maximum et gérer l’exception de la manière que l’on souhaite

 

Conclusion

A ce stade, les composants respectant le contrat couvrent déjà la plupart des cas d’utilisation. L’utilisation est simple et le composant est efficace. Il permet d’avoir une couche d’abstraction forte par rapport à l’utilisation de curl ou fopen en direct et ajoute même de l’abstraction supplémentaire face à des bundles comme guzzle (surtout avec la gestion des exceptions).

Les 20% restants des cas d’utilisation, c’est 80% du reste du contrat

Le reste des options

Les options couvrent 100% des cas d’utilisation d’un client http. C’est en tout cas le but de ce contrat.

  • proxy : pour définir un proxy
  • on_progress : pour afficher une barre de progression voir interrompre une requête
  • base_uri : pour n’utiliser par la suite que des url relative
  • max_redirects : pour limiter le nombre de redirection suivies automatiquement

Et bien d’autres :

 

Streamable upload and download

Pour l’upload, le body supporte pas mal de types qui permettent l’upload en mode stream

Pour le download, il est possible de stream la réponse par chunk

 

Dans l’exemple donné pendant la conférence, on désactive le buffer pour ne pas utiliser de mémoire temporaire puis on écrit chunk par chunk la réponse dans un fichier local. Oui, c’est aussi simple que ça.

 

Lazy & Concurrent

Il est possible de lancer des requêtes à la chaîne et elles seront réalisées en parallèle (avec comme limite le nombre de connections possibles auprès du end-point)

Pour traiter les réponses, deux solutions sont présentées par Nicolas Grekas :

Un foreach qui va attendre que la première soit finie avant de passer à la suivante et ainsi de suite :

A noter que les autres requêtes, même si on attend, sont tout de même réalisées en parallèle. Avec cette méthode nous allons attendre pour la/les premières mais les suivantes vont vite s’enchaîner puisqu’elles seront déjà chargées.

 

Un foreach mais avec du stream :

Cette méthode va traiter paquet par paquet et traiter les réponses dès qu’elles sont finies. A noter que l’on perd potentiellement l’ordre des requêtes faites plus haut.

 

Et les composants respectant le contrat ?

Nous venons de voir de belle promesses sous la forme d’un contrat mais nous n’avons pas encore vu les différentes implémentations qui existent aujourd’hui.

Deux implémentations principales sont d’ores et déjà existantes :

  • NativeHttpClient
  • CurlHttpClient

Les deux respectent entièrement le contrat httpClient et gèrent donc toutes les fonctionnalités citées plus haut.

D’autres implémentations peuvent être construites pour répondre à des besoins génériques ou spécifiques.

 

Les décorateurs

Symfony implémente le decoratorPattern : cela permet d’ajouter/modifier des fonctionnalités à un service. (https://symfony.com/doc/current/service_container/service_decoration.html)

Pour httpClient, des décorateurs sont déjà présents et utilisables :

  • ScopingHttpClient : permet d’automatiquement ajouter des informations sur les appels. Par exemple si vous utilisez httpClient pour appeler une API qui demande une authentification avec un bearer et que le endpoint est toujours le même, on peut utiliser le scopingHttpClient en le configurant avec une base_uri et un auth_bearer et tous les appels que l’on fera avec le scopingHttpClient seront automatiquement sur la base uri avec le token de remplis !

  • MockHttpClient : Un client qui permet de faire nos tests plus facilement. Pour le coup il ne fait aucun appel http.
  • CachingHttpClient : Rajoute un système de cache par dessus le httpClient

 

D’autres décorateurs sont déjà prévus et, comme le rappelle Nicolas Grekas, vous pouvez faire vos propres décorateurs (pour usage privé ou en open source ;) )

Et tout ça, c’est en plus autowired !

Dans l’exemple du scopedHttpClient on peut utiliser HttpClientInterface $githubClient pour le récupérer.

 

Conclusion

Le contrat httpClient est clairement un outil tourné vers l’avenir. Il va permettre aux projets d’être plus facilement maintenus car la montée en version, ou la modification, du système d’appel http sera facilité. Cette interface facilitera le développement de nos applications puisqu’elle sera unique bien qu’implémentée de façon différentes avec des primitives comme fopen ou curl. L’abstraction ajoute bien plus de facilité à l’utilisation et de nombreuses fonctionnalités sont présentes dans le contrat.

 

Conférence de Nicolas Grekas (@nicolasgrekas) à la Symfony Live Paris 2019

Slides originales : https://speakerdeck.com/nicolasgrekas/symfony-httpclient-what-else

 

Anthony C.

Ajouter un commentaire