Comment consommer l'API RESTful externe avec Symfony?

10

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 base de données. Lorsque Symfony gère généralement des entités avec Doctrine, automatisant la plupart du travail, cela ne peut pas être reproduit facilement lorsque nous devons accéder à des données externes à partir des API.

Par exemple, avec une entité Client:

  • En utilisant Doctrine, il suffit de définir notre classe Client, et il est désormais facile de créer, mettre à jour, récupérer nos clients
  • En utilisant l'approche API REST, 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 de toute autre manière?

Pierre B.
la source
Je suis dans le même bateau que toi. Consommation d'API externes avec des clients générés à partir des spécifications OpenApi / Swagger. Vous vous demandez quelles sont les meilleures pratiques pour le «cycle de vie» de la consommation, les opérations crud, les paramètres et la génération de forme de filtre Élargit actuellement ma recherche pour inclure toutes les approches, qu'elles soient spécifiques à Symfony ou non.
amont du
Ayant travaillé sur ce problème pendant plusieurs mois et revenant sur cette question, les deux réponses fournissent jusqu'à présent une solution similaire: la résiliation des appels api avec popo. C'est ainsi que nous avons fini par utiliser, bien qu'il existe d'autres solutions. Dans des contextes de communication API Webapp <> similaires, l'utilisation du niveau d'abstraction masquant les appels d'API de Webapp semble une bonne solution. Avec l'essor des microservices et des approches dirigées par les API, les meilleures pratiques et outils associés apparaîtront sans aucun doute pour résoudre ce qui semble être un problème commun.
Pierre B.
Ici, une approche similaire a été appliquée. La logique métier est maintenant contenue dans une couche «action», peu importe si c'est l'api REST ou une commande cli qui l'appelle. La conception hexagonale d'Alistair Cockburn était un excellent point de départ dans notre cas: alistair.cockburn.us/Hexagonal+architecture
amont le

Réponses:

2

J'ai créé un projet basé sur symfony qui utilise une API externe (JSON); j'ai créé une bibliothèque cliente indépendante ("bibliothèque cliente" - un logiciel, un package de compositeur), avec son propre ensemble d'entités (POPO); il s'intègre au framework à l'aide des interfaces fournies par Symfony (par exemple, en créant simplement un fournisseur d'utilisateurs 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é fait par des mappeurs, qui une fois écrits - ne changeaient pas très souvent (ou événement du tout). 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 à la façon dont le client devrait se comporter en cas de rupture de la connexion - le client devrait-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. Vous ne pourrez peut-être pas écrire de données entre-temps, mais vos utilisateurs pourront toujours parcourir les données mises en cache.

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

Jacek Kobus
la source
1

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.

accolade
la source