Architektura
ArchitekturaSerwer GraphQL code-first

Serwer GraphQL code-first

Schema GraphQL definiuje kontrakty usługi GraphQL, udostępniając zestaw typów, pól i mutacji, które można wykonywać na tej usłudze. Tworząc usługę GraphQL, możemy zdecydować się na:

  • uczynienie schematu źródłem prawdy i dostosowanie całego kodu implementacji do jego definicji
  • uczynienie kodu źródłem prawdy i generowanie schematu jako artefaktu na podstawie kodu

W obu przypadkach otrzymamy w pełni funkcjonalną usługę GraphQL, jednak w zależności od wybranego podejścia możemy realizować mniej lub więcej funkcji, z mniejszą lub większą łatwością, w dłuższej perspektywie. Te dwa podejścia noszą nazwy, odpowiednio, "schema-first" (trafniej: "SDL-first") oraz "code-first".

Gato GraphQL stosuje podejście code-first. Zobaczmy, dlaczego tak jest.

Dlaczego Gato GraphQL stosuje code-first

W podejściu code-first zaczynamy od kodowania resolverów, a następnie — z kodu jako jedynego źródła prawdy — generujemy schemat jako artefakt. Schemat jest więc tworzony przez uruchomienie skryptu, zamiast być tworzony ręcznie jak w SDL-first. Ponieważ code-first również posiada schemat, nie traci niczego istotnego z tego, co oferuje SDL-first.

Jednak code-first oferuje ważną cechę w porównaniu z SDL-first: możliwość dostarczania dynamicznych schematów, które mogą zmieniać swoją strukturę i atrybuty w zależności od kontekstu, regulowanych przez kod w czasie działania aplikacji. Rzeczywiście, wszystkie wspaniałe funkcje oferowane przez Gato GraphQL są bezpośrednią konsekwencją przyjęcia podejścia code-first.

Zalety podejścia code-first

Dynamiczny schemat oferuje między innymi wszystkie poniższe korzyści:

Źródło prawdy dla schematu jest nadzbiorem tego, czego wymaga GraphQL. Dodatkowe właściwości (takie jak pola globalne, połączenia globalne, globalne dyrektywy i utrwalone fragmenty) można już używać w naszym API bez konieczności czekania, aż zostaną dodane do specyfikacji GraphQL — jeśli w ogóle.

Ponieważ źródło prawdy nie jest powiązane ze schematem, możemy generować dowolny schemat dla dowolnego innego systemu: GraphQL jest tylko jednym z możliwych celów. Na przykład, z tego samego źródła prawdy można wygenerować JSON-schema dla usługi REST.

API może być jednocześnie publiczne/prywatne w zależności od tego, czy użytkownik jest zalogowany czy nie oraz jakie ma role, lub oferować mniej bądź więcej pól zależnie od innej właściwości, na przykład czy użytkownik wykupił subskrypcję PRO.

Typy nie wiedzą z góry, jakie pola będą rozwiązywać. Zamiast tego, resolvery pól przyłączają się do resolverów typów przy użyciu wzorca publish-subscribe, a resolvery pól mogą nadpisywać inne resolvery pól. Ta cecha sprawia, że API jest bardzo rozszerzalne, pozwalając nam posiadać ogólny kod dla naszego API i dostosowywać go na poziomie aplikacji dla konkretnego klienta lub projektu.

Pole może być przetwarzane nie tylko przez jeden, ale przez wiele resolverów pól: każdy resolver pola w łańcuchu może zdecydować w czasie działania aplikacji, czy przetworzyć pole na podstawie jakiejś właściwości, czy przekazać je dalej w łańcuchu. Na przykład specjalny resolver pola może być używany tylko wtedy, gdy zostanie przekazany argument pola "source: testing", umożliwiając testowanie na kilku witrynach produkcyjnych przed ogólnym wydaniem; ta sama strategia pozwala również dostarczać szybkie poprawki błędów dla konkretnego klienta lub środowiska bez ryzyka niezamierzonych efektów ubocznych w innych miejscach.

Typy i interfejsy mogą być automatycznie umieszczane w przestrzeniach nazw, aby uniknąć kolizji z bibliotekami zewnętrznymi.