web-dev-qa-db-fra.com

Comment consommer l'API RESTful externe avec Symfony?

Nous construisons une architecture de microservice pour nos projets, avec principalement des applications Symfony frontales interagissant avec des API RESTful dorsales.

Le problème est que cette approche brise la gestion des entités Symfony en s'appuyant fortement sur Doctrine avec la base de données. Lorsque Symfony gère généralement les entités avec Doctrine, automatisant la plupart du travail, cela ne peut pas être reproduit facilement lorsque nous devons accéder aux données externes à partir des API.

Par exemple, avec une entité Client:

  • En utilisant Doctrine, il nous suffit de définir notre classe Client, et il est maintenant facile de créer, mettre à jour, récupérer nos clients
  • En utilisant l'approche REST API, les clients sont accessibles via l'API, mais nous avons beaucoup de travail pour définir comment le client est créé (POST), mis à jour (PUT), récupéré (GET), etc.

A noter que les clients sont utilisés par plusieurs applications, pas seulement l'application frontale, d'où l'API dédiée.

Devrions-nous créer des classes avec des méthodes de type entité masquant la complexité des appels d'API, importer toutes les données d'API localement et y accéder via Doctrine ou toute autre manière?

10
Pierre B.

J'ai créé un projet basé sur symfony qui utilise une API externe (JSON); ce que j'ai fait était de créer une bibliothèque cliente indépendante ("bibliothèque cliente" - un logiciel, composer package), avec son propre ensemble d'entités (POPO); il s'intègre au framework en utilisant des interfaces fourni par Symfony (par exemple, en créant simplement un fournisseur d'utilisateur personnalisé ).

Le client effectue des appels http "en arrière-plan" - ce qui est important pour les futures capacités de test. Vous ne voulez pas exposer la façon dont vous communiquez avec votre source de données et vous ne voulez pas non plus que vos tests s'appuient sur une API en direct.

Interface de bibliothèque client (exemple à quoi elle peut ressembler):

class ApiClient {

   /**
    * @throws SomeApiException If credentials are invalid
    * @return ApiUser
    */
   public function authenticate($username, $password);

   /**
    * @return ApiUser
    */
   public function findUserByEmail($email);

   /**
    * @throws SomeApiException If email is invalid
    * @return void
    */
   public function changeUserEmail(User $user, $newEmail);
}

La bibliothèque cliente utilise en interne Guzzle pour la communication et le composant Doctrine Cache pour la mise en cache des résultats. Le mappage entre les objets d'entité et json a été effectué par des mappeurs, qui une fois écrits - ne changeaient pas très souvent (ou événement Dans ce cas, je suggère d'utiliser le JMS Serializer pour une transformation automatisée vers et depuis JSON (je suppose que vous utilisez JSON).

Vous aurez besoin d'un bon mécanisme de mise en cache et d'un stockage local, comme Redis. Faire des appels api sur chaque demande d'application va tuer votre serveur et ralentir considérablement votre application. Il est très important de comprendre le fonctionnement des caches http. Si votre API n'utilise pas les en-têtes de mise en cache (ou l'utilise de manière obscure), il sera très difficile et consommateur de ressources de suivre les modifications.

Vous voudrez également réfléchir au comportement du client en cas de rupture de la connexion - le client doit-il utiliser des données bloquées? Ce serait une bonne idée d'utiliser un serveur proxy entre votre application et l'API. Dans ce cas, le proxy (comme Varnish) pourrait accélérer vos demandes et également actualiser les données bloquées en arrière-plan sans ralentir votre application. Il gardera également votre site Web en ligne en cas de défaillance de l'API. Entre-temps, vous ne pourrez peut-être pas écrire de données, mais vos utilisateurs pourront toujours parcourir les données mises en cache.

Et en parlant de Doctrine, voir la " Loi de l'instrument ".

2
Jacek Kobus

Doctrine est une couche d'accès à la base de données. Vous ne voulez pas accéder à une base de données, mais aux API. Vous pouvez toujours créer une entité, mais comme un simple objet qui n'a pas à étendre notre implémentation (un popo). Il devrait avoir un référentiel qui implémente toutes les méthodes CRUD. Dans ce cas, appelle l'API au lieu de la base de données. Je créerais une interface pour ça. Il n'est pas nécessaire que votre application soit différente, sauf que vous devez tenir compte partout où un micro service peut ne pas répondre.

1
winkbrace

Pour info, il existe désormais un composant HttpClient pour la v4.3.

https://symfony.com/blog/new-in-symfony-4-3-httpclient-component

0
Fred Flint