fbpx

Wykorzystanie GraphQL w projekcie opartym o Django

 In Python, Technicznie

Z tego artykułu dowiesz się, w jaki sposób przygotować proste API przy użyciu GraphQL. Część serwerową napiszemy, jak zwykle, w Pythonie. Jako framework po stronie back-endu wykorzystamy Django, natomiast do obsługi samego GraphQL służyć nam będzie świetna biblioteka Graphene wraz z modułem Graphene-Django.

Jako zespół back-end deweloperów często tworzymy Web API, które pozwalają na komunikację naszego serwisu ze światem zewnętrznym – aplikacją mobilną, klientem napisanym np. w ReactJS czy aplikacją konsolową uruchamianą zadaniem cyklicznym. Dostarczając klasyczne REST API odwzorowujemy strukturę zasobów, jednak klient naszego API nie zawsze potrzebuje danych całego zasobu – z danych autora zgłoszenia może być istotne tylko imię, nazwisko i e-mail, a niekoniecznie jego dane adresowe.

Jednym z rozwiązań jest przygotowanie niestandardowych endpointów w API lub filtrowanie dostarczanych danych w zależności od parametrów w querystring’u, jednak to nie rozwiązuje problemu, gdy aplikacja kliencka potrzebuje pobrać strukturę obiektów zagnieżdżonych dalej niż jeden poziom – wtedy dla każdego obiektu zostanie wykonane odwołanie do API, co przy np. autorze posiadającym 10 książek, z których część ma współautorów, a listę tychże książek potrzebujemy mieć pogrupowaną według gatunku literackiego. W przypadku REST API taka struktura danych spowoduje albo wywołanie dziesiątek zapytań do API, a z otrzymanych danych otrzymamy tylko niewielką ich część, albo stworzenie niestandardowego endpointa (co szybko doprowadzi do sytuacji, gdzie dla większości przypadków użycia serwujemy niestandardowy endpoint, odbiegając od sensu funkcjonowania klasycznego REST API. Rozwiązaniem w takim przypadku może być wystawienie GraphQL’owego endpointa.

 

Ok, ale czym jest GraphQL?

GraphQL jest językiem zapytań, który pozwala nam na pobieranie i modyfikowanie danych ustrukturyzowanych w graf, z możliwością określenia, ile i jakich danych z powiązanych elementów faktycznie potrzebujemy. Początkowo istniał wewnętrznie w ramach Facebooka od roku 2012 (Facebook dla urządzeń mobilnych generował ponad 70% całkowitego ruchu w serwisie – użytkownicy po prostu lubią scrollować 🙂), natomiast w 2015 roku został udostępniony publicznie.

Możliwość zdefiniowania przez aplikację klienta (w przeciwieństwie do predefiniowanych zestawów danych w REST API) pozwala twórcy aplikacji klienckiej – niezależnie, czy jest to aplikacja webowa (w Angularze, Reakcie lub dowolnym innym frameworku), mobilna (natywna lub React Native), czy jest to zewnętrzne API, które potrzebuje komunikować się z naszym serwisem – w każdym z tych przypadków to konsument decyduje, ile i jakich danych pobierze, a po stronie backendu zapewniony musi być tylko dostęp do danych w taki sposób, aby klient mógł po nich nawigować, filtrować pola istotne dla niego oraz otrzymywać dane dokładnie w takiej postaci, w jakiej ich oczekuje.

Zasadniczo, w GraphQL wykorzystujemy dwa rodzaje poleceń: zapytania (queries) oraz mutacje (mutations). Zapytania pozwalają nam, jak sama nazwa wskazuje, na pobranie z backendu danych, które nam są potrzebne. Przykład:

Mamy po stronie backendu użytkowników (id, login, imię, nazwisko, email, url zdjęcia profilowego, aktualny status online/offline), którzy mają swoich przyjaciół. Potrzebujemy wyświetlić listę kontaktów użytkownika o id=1, więc musimy pobrać imiona i nazwiska oraz status online jego znajomych.

Zapytanie:

Odpowiedź:

Jak widać, odpowiednio konstruując zapytanie, otrzymaliśmy tylko te dane, które były nam potrzebne.

Użytkownik o id=1 chce zaktualizować swój adres e-mail, więc po wypełnieniu odpowiednich danych w aplikacji klienckiej może zostać wysłane następujące polecenie:

(w dalszej części artykułu  omówimy definicję typu UpdateEmailInput )

W odpowiedzi na powyższe zapytanie może otrzymać następującą odpowiedź:

Jak widać, pole e-mail wskazanego użytkownika zostało zaktualizowane.

W jednym z powyższych przykładów wykorzystaliśmy definicję typu UserEmailInput . Jak pewnie się domyślacie, pozwala nam ona na ustalenie struktury danych, które są potrzebne do wykonania polecenia (w tym przypadku mutacji). Przykładowa definicja typu:

Więcej o zapytaniach i mutacjach, jak również pozostałych możliwościach  w oficjalnej dokumentacji GraphQL.

A z punktu widzenia back-endowca?

Omówiliśmy w skrócie, jak możemy z GraphQL’a korzystać w aplikacji klienta, jednak potrzebujemy jeszcze źródła, z którego będziemy naszego GraphQL dostarczać. W przypadku projektu opartego o Django dobrym wyborem jest wykorzystanie biblioteki Graphene, która zapewnia nam integrację z Django. Dzięki niej w przyjemny sposób będziemy w stanie połączyć korzyści wynikające z użycia Django (modele, automatycznie generowane migracje, Django Admin) z samym GraphQL.

Bibliotekę dorzucamy do projektu poleceniem pipenv install graphene-django , następnie dodajemy ją do  INSTALLED_APPS  w pliku settings.py , a także definiujemy miejsce, gdzie znajduje się nasz schemat GraphQL’owego endpointa:

Następnie, w pliku urls.py definiujemy ścieżkę, z której będzie dostępny nasz endpoint:

Przygotujmy także prosty model danych ( app/models.py):

Teraz możemy przejść do definiowania schemy ( app/schema.py):

W tym momencie mamy gotowe przykładowe API oparte o GraphQL, do którego możemy tworzyć zapytania, a także dokonywać prostych zmian na istniejących danych.

Więcej o Graphene, przykłady oraz szczegółowy opis możliwości tej biblioteki dostępne są w dokumentacji.

Recommended Posts