Jak korzystać z zewnętrznego interfejsu API RESTful z Symfony?

10

Budujemy architekturę Microservice dla naszych projektów, głównie aplikacje frontowe Symfony współpracują z wewnętrznymi interfejsami API RESTful.

Problem polega na tym, że podejście to łamie zarządzanie jednostkami Symfony polegającymi w dużej mierze na Doctrine z bazą danych. Tam, gdzie Symfony zwykle obsługuje jednostki za pomocą Doctrine, automatyzując większość pracy, nie można tego łatwo odtworzyć, gdy musimy uzyskać dostęp do danych zewnętrznych z interfejsów API.

Na przykład z jednostką klienta:

  • Korzystając z Doctrine, musimy po prostu zdefiniować naszą klasę klienta, a teraz można łatwo tworzyć, aktualizować i odzyskiwać naszych klientów
  • Dzięki zastosowaniu interfejsu API REST klienci są dostępni za pośrednictwem interfejsu API, ale mamy wiele pracy, aby zdefiniować sposób tworzenia klienta (POST), aktualizowania (PUT), pobierania (GET) itp.

Należy zauważyć, że klienci używają kilku aplikacji, nie tylko aplikacji front-end, stąd dedykowany interfejs API.

Czy powinniśmy tworzyć klasy z metodami podobnymi do bytu, ukrywającymi złożoność wywołań API, importując wszystkie dane API lokalnie i uzyskując do nich dostęp za pośrednictwem Doctrine lub w inny sposób?

Pierre B.
źródło
Jestem na tej samej łodzi co ty. Wykorzystywanie zewnętrznych interfejsów API z klientami wygenerowanymi na podstawie specyfikacji OpenApi / Swagger. Zastanawiasz się nad najlepszymi praktykami w zakresie „cyklu życia” konsumpcji, operacji, parametrów i generowania form filtrów. Obecnie poszerzam moje wyszukiwanie o wszelkie podejścia, niezależnie od tego, czy jest to specyficzne dla Symfony, czy nie.
górę rzeki
Pracując nad tym problemem przez kilka miesięcy i wracając do tego pytania, obie odpowiedzi do tej pory zapewniają podobne rozwiązanie: abstrakcyjne wywołania interfejsu API za pomocą popo. Tak właśnie skończyliśmy, chociaż istnieją inne rozwiązania. W podobnych kontekstach komunikacyjnych API Webapp <> dobrym rozwiązaniem jest użycie poziomu abstrakcyjnego ukrywania wywołań API w Webapp. Wraz z pojawieniem się mikrousług i podejść opartych na interfejsie API bez wątpienia pojawią się powiązane najlepsze praktyki i narzędzia do rozwiązania tego, co wydaje się być powszechnym problemem.
Pierre B.
Tutaj zastosowano podobne podejście. Logika biznesowa jest teraz zawarta w warstwie „akcji”, która nie ma znaczenia, czy jest to interfejs API REST, czy wywołujące ją polecenie cli. Sześciokątna konstrukcja Alistaira Cockburna była świetnym punktem wyjścia w naszym przypadku: alistair.cockburn.us/Hexagonal+architecture
upstream

Odpowiedzi:

2

Zrobiłem projekt oparty na symfony, który używa zewnętrznego API (JSON); to, co zrobiłem, to stworzenie niezależnej biblioteki klienta („biblioteka klienta” - oprogramowanie, pakiet kompozytora), z własnym zestawem jednostek (POPO); integruje się ze strukturą za pomocą interfejsów dostarczanych przez Symfony (na przykład, po prostu tworząc niestandardowego dostawcę użytkownika ).

Klient wykonuje połączenia HTTP „za kulisami” - jest to ważne dla przyszłych możliwości testowania. Nie chcesz ujawniać sposobu komunikacji ze źródłem danych, a także nie chcesz, aby testy opierały się na interfejsie API na żywo.

Interfejs biblioteki klienta (przykład jak może to wyglądać):

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

Biblioteka klienta wewnętrznie używa Guzzle do komunikacji i komponentu Doctrine Cache do buforowania wyników. Odwzorowanie między obiektami encji a Jsonem zostało wykonane przez twórców mapowania, którzy raz napisali - nie zmieniali się bardzo często (ani wcale zdarzeń). W takim przypadku sugerowałbym użycie JMS Serializer do automatycznej transformacji do i z JSON (zakładam, że używasz JSON).

Będziesz potrzebował dobrego mechanizmu buforowania i lokalnego magazynu, takiego jak Redis. Wykonywanie api-połączeń przy każdym żądaniu aplikacji zabije serwer i drastycznie spowolni aplikację. Bardzo ważne jest, aby zrozumieć, jak działają pamięci podręczne http. Jeśli twój interfejs API nie używa buforujących nagłówków (lub używa go w niejasny sposób), śledzenie zmian będzie bardzo trudne i pochłania zasoby.

Zastanów się także, jak powinien zachowywać się klient, jeśli połączenie zostanie zerwane - czy klient powinien użyć zablokowanych danych? Dobrym pomysłem byłoby użycie serwera proxy między aplikacją a interfejsem API. W takim przypadku serwer proxy (np. Varnish) może przyspieszyć żądania, a także odświeżyć zablokowane dane w tle bez spowalniania aplikacji. Utrzyma również twoją stronę internetową w przypadku awarii interfejsu API. W międzyczasie możesz nie być w stanie zapisywać danych, ale użytkownicy nadal będą mogli przeglądać dane w pamięci podręcznej.

Mówiąc o doktrynie, patrz „ Prawo instrumentu ”.

Jacek Kobus
źródło
1

Doctrine to warstwa dostępu do bazy danych. Nie chcesz uzyskać dostępu do bazy danych, ale apis. Nadal możesz utworzyć Encję, ale potem jako prosty obiekt, który nie musi nic rozszerzać naszej implementacji (popo). Powinien mieć repozytorium, które implementuje wszystkie metody CRUD. W takim przypadku wywołania interfejsu API zamiast bazy danych. Stworzyłbym do tego interfejs. Aplikacja nie musi wyglądać inaczej, z wyjątkiem tego, że musisz wziąć pod uwagę wszędzie tam, gdzie mikro usługa może nie odpowiedzieć.

winkbrace
źródło