Como consumir API RESTful externa com Symfony?

10

Estamos construindo uma arquitetura de Microservice para nossos projetos, com aplicativos Symfony de front-end interagindo com APIs RESTful de back-end.

O problema é que essa abordagem está interrompendo o gerenciamento de entidades do Symfony, dependendo fortemente do Doctrine com o banco de dados. Onde o Symfony geralmente lida com entidades com o Doctrine, automatizando a maior parte do trabalho, isso não pode ser reproduzido facilmente quando precisamos acessar dados externos das APIs.

Por exemplo, com uma entidade cliente:

  • Usando o Doctrine, apenas precisamos definir nossa classe Client, e agora é fácil criar, atualizar, recuperar nossos clientes.
  • Usando a abordagem da API REST, os clientes são acessíveis por meio da API, mas temos muito trabalho para definir como o cliente é criado (POST), atualizado (PUT), recuperado (GET) etc.

Observe que os clientes são usados ​​por vários aplicativos, não apenas pelo aplicativo front-end, portanto, pela API dedicada.

Devemos criar classes com métodos semelhantes a entidades que ocultam a complexidade das chamadas da API, importando todos os dados da API localmente e acessá-los através do Doctrine, ou de qualquer outra maneira?

Pierre B.
fonte
Estou no mesmo barco que você. Consumir APIs externas com clientes gerados a partir das especificações do OpenApi / Swagger. Pensando nas melhores práticas para o ciclo de vida do consumo, operações brutas, parâmetros e geração de formulários de filtros. No momento, estou expandindo minha pesquisa para incluir abordagens, independentemente de ser específica ou não do Symfony.
upstream
Tendo trabalhado nesse problema por vários meses e voltado a essa questão, as duas respostas até agora fornecem uma solução semelhante: abstrair as chamadas da API com o popo. Foi assim que acabamos usando, embora existam outras soluções. Em contextos similares de comunicação da API Webapp <>, o uso de chamadas de API ocultas no nível de abstração do Webapp parece uma boa solução. Com o surgimento de microsserviços e abordagens de API-Lead, surgirão sem dúvida as melhores práticas e ferramentas relacionadas para resolver o que parece ser um problema comum.
Pierre B.
Por aqui, uma abordagem semelhante foi aplicada. A lógica de negócios agora está contida em uma camada de 'ação', que não se importa se é a API REST ou um comando cli que a chama. O design hexagonal de Alistair Cockburn foi um ótimo ponto de partida no nosso caso: alistair.cockburn.us/Hexagonal+architecture
upstream

Respostas:

2

Eu fiz um projeto baseado no symfony que está usando uma API externa (JSON); o que fiz foi criar uma biblioteca cliente independente ("client library" - um software, pacote compositor), com seu próprio conjunto de entidades (POPOs); ele se integra à estrutura usando as interfaces fornecidas pelo Symfony (por exemplo, simplesmente criando um provedor de usuário personalizado ).

O cliente faz chamadas http "nos bastidores" - isso é importante para futuros recursos de teste. Você não deseja expor a maneira como se comunica com sua fonte de dados e também não deseja que seus testes confiem na API ao vivo.

Interface da biblioteca do cliente (exemplo como pode ser):

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);
}

A biblioteca cliente usa internamente o Guzzle para comunicação e o componente Doctrine Cache para armazenar em cache os resultados. O mapeamento entre objetos de entidade e json foi feito por mapeadores, que uma vez escritos - não mudavam com muita frequência (ou evento). Nesse caso, sugiro o uso do serializador JMS para uma transformação automatizada de e para JSON (presumo que você use JSON).

Você precisará de um bom mecanismo de armazenamento em cache e armazenamento local, como o Redis. Fazer chamadas de API em cada solicitação de aplicativo matará seu servidor e diminuirá drasticamente seu aplicativo. É muito importante entender como os caches http funcionam. Se a sua API não usar cabeçalhos de armazenamento em cache (ou usá-lo de maneira obscura), será muito difícil e consumirá recursos acompanhar as alterações.

Você também deve pensar em como o cliente deve se comportar se a conexão for interrompida - o cliente deve usar dados paralisados? Seria uma boa ideia usar um servidor proxy entre seu aplicativo e a API. Nesse caso, o proxy (como o Varnish) pode acelerar suas solicitações e também atualizar dados paralisados ​​em segundo plano sem diminuir a velocidade do aplicativo. Ele também manterá seu site on-line em caso de falha na API. Enquanto isso, talvez você não consiga gravar dados, mas seus usuários ainda poderão procurar dados em cache.

E por falar em Doutrina, veja a " Lei do instrumento ".

Jacek Kobus
fonte
1

A doutrina é uma camada de acesso ao banco de dados. Você não deseja acessar um banco de dados, mas apis. Você ainda pode criar uma Entidade, mas como um objeto simples que não precisa estender nada para implementar (um popo). Ele deve ter um repositório que implemente todos os métodos CRUD. Nesse caso, chama a API em vez do banco de dados. Eu criaria uma interface para isso. Não precisa parecer diferente para o seu aplicativo, exceto que você deve levar em consideração em todos os lugares que um micro serviço pode não responder.

winkbrace
fonte