¿Cómo consumir API RESTful externa con Symfony?

10

Estamos construyendo una arquitectura de microservicios para nuestros proyectos, con la mayoría de las aplicaciones Symfony front-end interactuando con las API RESTful de back-end.

El problema es que este enfoque está rompiendo la administración de la entidad Symfony que depende en gran medida de Doctrine con base de datos. Donde Symfony generalmente maneja entidades con Doctrine, automatizando la mayor parte del trabajo, esto no se puede reproducir fácilmente cuando tenemos que acceder a datos externos desde las API.

Por ejemplo, con una entidad Cliente:

  • Usando Doctrine, solo tenemos que definir nuestra clase de Cliente, y ahora es fácil crear, actualizar, recuperar a nuestros clientes
  • Usando el enfoque REST API, se puede acceder a los clientes a través de la API, pero tenemos mucho trabajo para definir cómo se crea (POST), se actualiza (PUT), se recupera (GET), etc.

Cabe señalar que los clientes son utilizados por varias aplicaciones, no solo la aplicación front-end, de ahí la API dedicada.

¿Deberíamos crear clases con métodos similares a entidades que oculten la complejidad de las llamadas API, importando todos los datos API localmente y accedan a ellos a través de Doctrine, o de cualquier otra manera?

Pierre B.
fuente
Estoy en el mismo bote que tú. Consumir API externas con clientes generados a partir de las especificaciones OpenApi / Swagger. Preguntándose acerca de las mejores prácticas para el consumo del 'ciclo de vida', las operaciones crudas, los parámetros y la generación de formas de filtro. Actualmente estoy ampliando mi búsqueda para incluir cualquier enfoque, independientemente de si es específico de Symfony o no.
corriente arriba
Después de haber trabajado en este problema durante varios meses y volviendo a esta pregunta, ambas respuestas hasta ahora proporcionan una solución similar: abstraer las llamadas api con popo. Así es como terminamos usando, aunque existen otras soluciones. En contextos similares de comunicaciones API Webapp <>, usar el nivel de abstracción ocultando llamadas API de la Webapp parece una buena solución. Con el aumento de los microservicios y los enfoques de API-lead, sin duda surgirán las mejores prácticas y herramientas relacionadas para resolver lo que parece ser un problema común.
Pierre B.
Por aquí se aplicó un enfoque similar. La lógica empresarial ahora está contenida en una capa de 'acción', a la que no le importa si es la API REST o un comando cli que la llama. El diseño hexagonal de Alistair Cockburn fue un gran punto de partida en nuestro caso: alistair.cockburn.us/Hexagonal+architecture
upstream

Respuestas:

2

Hice un proyecto basado en Symfony que usa una API externa (JSON); lo que hice fue crear una biblioteca cliente independiente ("biblioteca cliente" - una pieza de software, paquete compositor), con su propio conjunto de entidades (POPO); se integra con el marco utilizando interfaces proporcionadas por Symfony (por ejemplo, simplemente creando un proveedor de usuario personalizado ).

El cliente realiza llamadas http "detrás de escena", lo cual es importante para futuras capacidades de prueba. No desea exponer la forma en que se comunica con su fuente de datos y tampoco desea que sus pruebas dependan de la API en vivo.

Interfaz de la biblioteca del cliente (ejemplo, cómo puede verse):

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 biblioteca del cliente utiliza internamente Guzzle para la comunicación y el componente Doctrine Cache para almacenar en caché los resultados. El mapeo entre objetos de entidad y json fue realizado por mapeadores, que una vez escritos, no cambiaron muy a menudo (o evento en absoluto). En este caso, sugeriría usar el serializador JMS para una transformación automática hacia y desde JSON (supongo que usa JSON).

Necesitará un buen mecanismo de almacenamiento en caché y almacenamiento local, como Redis. Hacer llamadas de API en cada solicitud de aplicación matará a su servidor y ralentizará drásticamente su aplicación. Es muy importante entender cómo funcionan los cachés http. Si su API no usa encabezados de almacenamiento en caché (o los usa de una manera oscura), será muy difícil y consumirá muchos recursos realizar un seguimiento de los cambios.

También querrá pensar en cómo debería comportarse el cliente si se corta la conexión. ¿Debería el cliente usar datos estancados? Sería una buena idea utilizar algún servidor proxy entre su aplicación y la API. En este caso, el proxy (como Varnish) podría acelerar sus solicitudes y también actualizar los datos detenidos en segundo plano sin ralentizar su aplicación. También mantendrá su sitio web en línea en caso de falla de la API. Es posible que no pueda escribir datos mientras tanto, pero sus usuarios aún podrán examinar los datos almacenados en caché.

Y hablando de Doctrina, vea la " Ley del instrumento ".

Jacek Kobus
fuente
1

Doctrine es una capa de acceso a la base de datos. No desea acceder a una base de datos, sino apis. Todavía puede crear una Entidad, pero luego como un objeto simple que no tiene que extender nada de nuestro implemento (un popo). Debe tener un repositorio que implemente todos los métodos CRUD. En este caso, llama a la API en lugar de a la base de datos. Crearía una interfaz para eso. No tiene que sentirse diferente para que su aplicación lo use, excepto que debe tener en cuenta en todas partes que un micro servicio podría no responder.

winkbrace
fuente