GraphQL Mutations – zapis danych do bazy

424
views

W pierwszym poście dotyczącym implementacji GraphQL w projekcie PHPowym opisałem w skrócie najważniejsze elementy tego narzędzia, dlatego jeśli nie masz jeszcze żadnej wiedzy na ten temat to możesz do niego skoczyć aby w szybki sposób poznać podstawy.

Dzisiaj chciałbym omówić kwestię modyfikacji danych na prostym przykładzie dodania nowego elementu do bazy dancyh.

Mutation

Na początek w schemacie naszego API trzeba dodać do typu Mutation akcję, którą chcemy wykonać. Poniżej prosta mutacja zawierająca tylko jedną operację createBox.

W 10 linii zadeklarowano mutację createBox, która będzie tworzyć nowy element w naszym systemie. 11 linia to deklaracja typu zapytania, który determinuje co powinno zostać zwrócone po wykonaniu zadania. Kolejna linia to deklaracja argumentów, których oczekujemy od klienta, w tym wypadku oczekiwana jest tylko nazwa dla nowego elementu.

W linii 18 deklarowana jest funkcja anonimowa, która odpowiada za wykonanie niezbędnych akcji i zwrócenie danych w formacie zgodnym z typem.

Funkcja anonima resolve obsługuje 3 parametry:

  • $rootValue – wartość, która może zostać przekazana od samego korzenia grafu (w momencie deklarowania schematu API).
  • $args – argumenty przekazane przez klienta (według schematu zadeklarowanego w 12 linii kodu).
  • $context – to wartość również przekazywana od samego korzenia, mogą tam być dodane takie iformacje jak zalogowany użytkownik. W wypadku mojej aplikacji przekazuję instancję DIC (Dependency Injection Container) w którym przechowuję m.in. połączenie z bazą danych.

Deklaracja typu dla tworzenia nowego elementu w tym wypadku wygląda tak jak na poniższym listingu.

Jeśli nowy element Box zostanie poprawnie utworzony to zostanie zwrócony element typu Box, a jeśli coś poszło nie tak jak powinno bądź wprowadzony argument był niepoprawny odpowiednie informacje zostaną przekazane w polu errors.

Akcja

Znasz wzorzec MVC? Pewnie, że znasz. W większości aplikacji kontrolery to klasy, które zawierają w sobie metody będące akcjami, ja w tym wypadku podszedłem do tego trochę inaczej wzorując się na artykule Macieja Aniserowicza Kontroler jest jak wyrostek.

Za każdym razem kiedy wykonywane jest zapytanie do API tworzona jest nowa instancja obiektu reprezentującego akcję. Zgodnie z zasadą DIP do konstruktora przekazywane są wszystkie komponenty, z których będzie korzystać akcja.

Na powyższym listingu konkretne zadanie wykonywane jest w liniach 27 i 28, reszta to obsługa błędów itp. Logika tworzenia nowego elementu i tak jest ukryta na niższych warstwach aplikacji, których teraz nie będę już tutaj przeklejać. Po krótce wykonywana jest walidacja danych wejściowych, następnie tworzony jest obiekt Box i na jego podstawie odbywa się zapis nowego elementu do bazy danych.

Obsługa błędów w GraphQL – jak poradzić sobie bez kodu odpowiedzi?

Przy tradycyjnym REST API mamy cały zestaw kodów odpowiedzi dla różnego wyniku rządania, np. dla niepoprawnych danych wejściowych zwrócilibyśmy kod 400, ale przy GraphQL nie jest to takie oczywiste. Trzeba wprowadzić swój schemat obsługi błędów.

Jak działa obsługa wyjątków na przykładzie tej samej akcji opisałem w poprzednim poście. Warto go przejrzeć aby lepiej zrozumieć koncepcję obsługi błędów.

Do klienta zwracana jest tablica według typu CreateBoxType zaprezentowanego wcześniej. Jeśli wszystko się powiodło to zwracana jest tablica, gdzie element box przyjmuje dane dla nowo utworzonego elementu, a errors jest wartością null. W przeciwnym razie (jeśli wystąpiły jakieś błędy) element box posiada wartość null, a w polu errors ustawiana jest wartość według typu ErrorType zaprezentowanego poniżej.