Wstęp
W świecie rozwijających się technologii i coraz bardziej zaawansowanych aplikacji internetowych, elastyczność i wydajność API stają się kluczowymi elementami sukcesu. W tym artykule przyjrzymy się innowacyjnemu podejściu do zarządzania danymi w API – GraphQL. Pozwala ono na bardziej precyzyjne i elastyczne zapytania. Omówimy, jak zintegrować to podejście z naszą aplikacją Symfony, korzystając z API Platform. Pomoże jeszcze lepiej dostosować nasze API do potrzeb klientów. Ten artykuł jest częścią serii, w której uczymy się, jak tworzyć i zarządzać API, aby współpracować z różnymi aplikacjami i narzędziami.
Opracowane przez Facebook, GraphQL to język zapytań oraz środowisko wykonawcze, które stanowią alternatywę dla tradycyjnych podejść opartych na REST. Największą zaletą tego podejścia jest możliwość pobierania tylko tych danych, które są rzeczywiście potrzebne. Pozwala to na oszczędność zasobów oraz zwiększenie wydajności naszego API.
W dalszej części artykułu przedstawię krok po kroku, jak zintegrować to rozwiązanie z aplikacją Symfony, korzystając z biblioteki webonyx/graphql-php. Następnie, na konkretnych przykładach, pokażę, jak tworzyć zapytania, aby uzyskać żądane dane, a także jak korzystać z różnorodnych funkcji, takich jak filtrowanie, sortowanie czy paginacja, które dodatkowo ułatwiają pracę z danymi. Omówię również jak obsługiwać błędy oraz jak dostosować API, aby spełniało potrzeby różnych klientów, przy jednoczesnym zachowaniu wydajności i elastyczności.
Instalacja GraphQL
Aby zintegrować GraphQL z naszą aplikacją Symfony, musimy zainstalować bibliotekę webonyx/graphql-php, która pozwoli na obsługę tego języka zapytań. Wykonaj poniższe polecenie, aby zainstalować wymagane zależności:
composer require webonyx/graphql-php
Po zainstalowaniu biblioteki, w naszej aplikacji zostaną utworzone nowe trasy, dzięki którym będziemy mogli korzystać z GraphQL:
- /api/graphql: To jest główny punkt wejścia dla naszego API opartego na GraphQL. Wszystkie zapytania GraphQL są wysyłane do tego endpointu, zarówno dla zapytań (queries) jak i mutacji (mutations).
- /api/graphql/graphiql: GraphiQL to interaktywne środowisko do eksplorowania naszego API opartego na GraphQL, które pozwala na tworzenie i testowanie zapytań bezpośrednio w przeglądarce. Jest to bardzo użyteczne narzędzie, szczególnie podczas etapu tworzenia i debugowania naszego API.
- /api/graphql/graphql_playground: GraphQL Playground to kolejne narzędzie do eksploracji i testowania naszego API, które oferuje nieco więcej funkcji niż GraphiQL. Umożliwia ono nie tylko tworzenie i testowanie zapytań, ale także dostarcza lepsze wsparcie dla dokumentacji, zarządzania nagłówkami oraz podglądu schematu GraphQL.
Po zainstalowaniu biblioteki webonyx/graphql-php i utworzeniu odpowiednich tras, nasza aplikacja Symfony jest gotowa do obsługi zapytań. Dzięki integracji GraphQL z API Platform, możemy łatwo zarządzać zarówno zasobami opartymi na RESTful, jak i zasobami opartymi na GraphQL. To zapewnia większą elastyczność i lepsze dostosowanie API do potrzeb klientów, niezależnie od wykorzystywanych przez nich technologii.
Schemat GraphQL i pierwsze zapytanie
Gdy mamy już zainstalowane wszystkie potrzebne komponenty, czas na stworzenie schematu GraphQL oraz przeprowadzenie naszego pierwszego zapytania. Schemat GraphQL to struktura definiująca typy, zapytania, mutacje oraz subskrypcje dostępne w naszym API. Zawiera informacje o tym, jakie dane można pobrać, jakie operacje można wykonać oraz jakie są relacje między poszczególnymi typami.
Tworzenie schematu GraphQL
Aby stworzyć schemat GraphQL, musimy zdefiniować typy danych, które będą dostępne w naszym API. Następnie musimy określić, jakie zapytania i mutacje są dozwolone. Przykładowo, w naszej aplikacji możemy zdefiniować schemat dla encji Person:
type Person {
id: ID!
name: String!
surname: String!
age: Int!
email: String!
}
W powyższym schemacie definiujemy typ Person
z pięcioma polami: id
, name
, surname
, age
i email
. Wykrzyknik oznacza, że pole jest wymagane. Teraz możemy zdefiniować zapytania i mutacje, które będą dostępne w naszym API.
type Query {
person(id: ID!): Person
allPeople: [Person]
}
type Mutation {
createPerson(name: String!, surname: String!, age: Int!, email: String!): Person
updatePerson(id: ID!, name: String, surname: String, age: Int, email: String): Person
deletePerson(id: ID!): Boolean
}
W powyższym przykładzie definiujemy trzy zapytania: person
, które pozwala na pobranie danych pojedynczej osoby na podstawie id
, allPeople
, które zwraca listę wszystkich osób, oraz mutacje: createPerson
, updatePerson
i deletePerson
, które pozwalają na tworzenie, aktualizowanie i usuwanie osób.
W naszej aplikacji, dzięki zastosowaniu anotacji #[ApiResource]
w encji Person, API Platform automatycznie generuje odpowiednie typy i zapytania GraphQL dla tej encji. Więc nie musimy ręcznie definiować schematu GraphQL, jak wcześniej wspomniano.
Wykonywanie pierwszego zapytania GraphQL
Teraz, gdy mamy już skonfigurowane GraphQL w naszej aplikacji Symfony, możemy przetestować jego działanie, wykonując pierwsze zapytanie. Aby to zrobić, przejdź do ścieżki /api/graphql
w przeglądarce. Zobaczysz interfejs GraphiQL, który pozwala na wprowadzenie zapytań GraphQL oraz eksplorowanie dostępnych typów i pól w naszym schemacie.
Aby wykonać zapytanie, które zwróci listę osób, wraz z ich identyfikatorami, imionami, nazwiskami i adresami e-mail, wprowadź poniższy kod w lewym panelu GraphiQL:
{
people {
edges {
node {
id
name
surname
email
}
}
}
}
Następnie kliknij przycisk „Execute” (lub użyj skrótu klawiszowego Ctrl + Enter), aby wysłać zapytanie. W prawym panelu zobaczysz wyniki zapytania w formacie JSON, zawierające informacje o osobach zapisanych w naszej aplikacji. W wynikach zauważysz, że dane są zorganizowane w strukturze zgodnej z zapytaniem. Widzimy je zagnieżdżone w polach „people”, „edges” i „node”. Ta struktura jest typowa dla zapytań GraphQL, które pobierają listy danych. Pozwala to na obsługę paginacji i łatwe przeglądanie wyników zapytania.
Stronicowanie wyników zapytań w GraphQL
Paginacja jest kluczowym elementem każdego API, które zwraca dużą liczbę rekordów. Pozwala na ładowanie mniejszych porcji danych, co przyspiesza czas odpowiedzi i zmniejsza obciążenie zarówno dla użytkowników końcowych, jak i serwera. API Platform używa mechanizmu paginacji opartego na kursorach. Domyślnie, paginacja jest włączona, a strona wyników zawiera 30 rekordów. Aby kontrolować, które strony rekordów są zwracane, możesz użyć argumentów first
, last
, before
i after
w zapytaniach GraphQL. Omówimy, jak używać paginacji w zapytaniach GraphQL.
Przykład paginacji: Pobieranie 10 pierwszych rekordów
Aby pobrać 10 pierwszych rekordów, możemy użyć argumentu first
w zapytaniu GraphQL. Oto przykład zapytania z paginacją:
query {
people(first: 10) {
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
edges {
cursor
node {
id
name
surname
email
}
}
}
}
W odpowiedzi otrzymasz informacje o paginacji w polu pageInfo
, które zawiera informacje o dostępnościności następnych i poprzednich stron, oraz kursorach dla początku i końca aktualnej strony wyników. Oto przykład odpowiedzi:
{
"data": {
"people": {
"pageInfo": {
"hasNextPage": true,
"hasPreviousPage": false,
"startCursor": "MA==",
"endCursor": "OQ=="
},
"edges": [
{
"cursor": "MA==",
"node": {
"id": "/api/people/1",
"name": "Ismael",
"surname": "Hessel",
"email": "dillon.quitzon@example.com"
}
},
//...
]
}
}
}
Przykład paginacji: Pobieranie kolejnych rekordów
Teraz, gdy mamy wyniki pierwszego zapytania, możemy przejść do kolejnych rekordów, używając kursora endCursor
. W odpowiedzi powyżej wartość endCursor
wynosi "OQ=="
. Użyjmy tego kursora, aby pobrać kolejne 10 rekordów:
query {
people(first: 10, after: "OQ==") {
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
edges {
cursor
node {
id
name
surname
email
}
}
}
}
Wykonując powyższe zapytanie, otrzymasz kolejne 10 rekordów, zaczynając od 11. rekordu. W odpowiedzi otrzymasz również zaktualizowane informacje o paginacji w polu pageInfo
, w tym informacje o dostępności następnych i poprzednich stron oraz kursorach dla początku i końca aktualnej strony wyników.
Jeśli chcesz kontynuować paginację, po prostu powtórz ten proces, używając wartości endCursor
z odpowiedzi na poprzednie zapytanie. W ten sposób będziesz mógł przeglądać wszystkie rekordy, paginując je w miarę potrzeb.
Podsumowując, paginacja umożliwia efektywne przeglądanie dużych zbiorów danych, dzięki czemu można ładować mniejsze porcje danych w miarę potrzeb. Dzięki paginacji można zmniejszyć obciążenie serwera i zapewnić lepszą wydajność dla użytkowników końcowych.
Dodawanie nowych rekordów za pomocą mutacji GraphQL
W GraphQL, mutacje są odpowiedzialne za modyfikowanie danych na serwerze, w tym za tworzenie nowych rekordów. Aby dodać nowy rekord, musimy zdefiniować mutację w naszym schemacie GraphQL. W naszym przypadku chcemy dodać nową osobę do naszej aplikacji, więc dodamy mutację createPerson
.
Jeśli skorzystaliśmy z automatycznie generowanego schematu przez API Platform, mutacje są już dostępne. Otwórz interfejs GraphiQL lub GraphQL Playground i wpisz następujące zapytanie:
mutation {
createPerson(input: {
name: "Jan",
surname: "Kowalski",
age: 32,
email: "jan.kowalski@example.com"
}) {
person {
id
name
surname
age
email
}
}
}
W zapytaniu mutacji powyżej, używamy słowa kluczowego mutation
, a następnie definiujemy naszą mutację createPerson
. Podajemy wartości dla wszystkich wymaganych pól (name
, surname
, age
, email
) wewnątrz obiektu input
. Po wykonaniu tej mutacji, serwer doda nową osobę do bazy danych z podanymi wartościami i zwróci utworzony rekord. W odpowiedzi na zapytanie oczekujemy, że otrzymamy obiekt person
zawierający identyfikator, imię, nazwisko, wiek i adres e-mail nowo utworzonej osoby.
Wciśnij przycisk „Execute” lub „Uruchom” w interfejsie GraphiQL lub GraphQL Playground, aby wykonać zapytanie. Jeśli wszystko zostało wykonane poprawnie, otrzymasz odpowiedź zawierającą dane nowo utworzonej osoby, przykładowo:
{
"data": {
"createPerson": {
"person": {
"id": "/api/people/102",
"name": "Jan",
"surname": "Kowalski",
"age": 32,
"email": "jan.kowalski@example.com"
}
}
}
}
W ten sposób dodaliśmy nową osobę do naszej aplikacji za pomocą mutacji GraphQL. W kolejnych sekcjach artykułu omówimy inne operacje, takie jak aktualizowanie istniejących rekordów oraz usuwanie rekordów za pomocą mutacji GraphQL.
Ważną zaletą korzystania z tego rozwiązania w naszej aplikacji jest możliwość dokładnego określenia danych, które chcemy otrzymać w odpowiedzi na nasze zapytania oraz operacje mutacji. Dzięki temu uzyskujemy większą elastyczność i kontrolę nad przesyłanymi danymi, co może prowadzić do znacznego zwiększenia wydajności aplikacji, szczególnie na urządzeniach mobilnych z ograniczonymi zasobami i przepustowością łącza.
Aktualizacja rekordów za pomocą mutacji GraphQL
Aby zaktualizować istniejący rekord za pomocą GraphQL, możemy użyć mutacji updatePerson
. Mutacja ta przyjmuje argument input
, który zawiera dane rekordu, który chcemy zaktualizować, w tym również identyfikator rekordu. Oto jak zaktualizować rekord o identyfikatorze „/api/people/102” w naszym API:
Otwórz narzędzie do eksploracji GraphQL. Wprowadź następujące zapytanie w okno zapytań:
mutation {
updatePerson(input: {
id: "/api/people/102",
name: "Jan",
surname: "Nowak",
age: 35,
email: "jan.nowak@example.com"
}) {
clientMutationId
person {
id
name
surname
age
email
}
}
}
Wykonaj zapytanie, naciskając przycisk „Wykonaj” (w przypadku GraphiQL) lub odpowiedni przycisk w innym narzędziu eksploracji. Po wykonaniu zapytania, w oknie wyników powinieneś zobaczyć zaktualizowany rekord:
{
"data": {
"updatePerson": {
"clientMutationId": null,
"person": {
"id": "/api/people/102",
"name": "Jan",
"surname": "Nowak",
"age": 35,
"email": "jan.nowak@example.com"
}
}
}
}
Teraz, gdy otrzymaliśmy zaktualizowany rekord, możemy zweryfikować, czy zmiany zostały prawidłowo zastosowane w naszym API. Sprawdź, czy wartości `name`, `surname`, `age` i `email` odpowiadają wartościom, których oczekiwałeś. W przypadku potrzeby aktualizacji tylko niektórych pól, wystarczy dodać tylko te pola do argumentu `input`. Na przykład, aby zaktualizować jedynie imię osoby, można użyć następującego zapytania:
mutation {
updatePerson(input: {
id: "/api/people/102",
name: "Jan"
}) {
clientMutationId
person {
id
name
surname
age
email
}
}
}
W wyniku tego zapytania, tylko pole name
zostanie zaktualizowane, a pozostałe pola pozostaną niezmienione.
Usuwanie rekordów za pomocą mutacji GraphQL
Aby usunąć istniejący rekord za pomocą mutacji GraphQL, użyjemy mutacji deletePerson
. Przygotujmy zapytanie, które usunie rekord o ID /api/people/102
:
mutation {
deletePerson(input: {id: "/api/people/102"}) {
clientMutationId
}
}
Przejdź do swojego interfejsu GraphQL, a następnie wklej powyższe zapytanie w okno zapytań. Kliknij przycisk „Wykonaj” lub użyj skrótu klawiszowego (np. Ctrl+Enter), aby wysłać zapytanie. Jeśli operacja zakończyła się sukcesem, otrzymasz odpowiedź w postaci:
W zapytaniu tym, argument input
zawiera id
rekordu, który chcemy usunąć. Jeśli usunięcie rekordu się powiedzie, otrzymasz odpowiedź z wartością clientMutationId
:
{
"data": {
"deletePerson": {
"clientMutationId": null
}
}
}
Aby sprawdzić, czy rekord został rzeczywiście usunięty, możemy wykonać zapytanie konkretny id:
query {
person(id: "/api/people/101") {
id
name
surname
age
email
}
}
Jeśli rekordu nie ma otrzymamy taką odpowiedź:
{
"data": {
"person": null
}
}
Korzyści z GraphQL
Warto wspomnieć, dlaczego warto wykorzystać to innowacyjne podejście w naszej aplikacji. Oto kilka głównych korzyści:
- Elastyczność: Pozwala klientom na żądanie konkretnych pól, których potrzebują, co pozwala im na optymalizację wydajności oraz redukcję transferu danych.
- Silna typizacja: Dzięki temu rozwiązaniu, każde pole w zapytaniu musi być zgodne z typem danych. Pomaga to w wykrywaniu błędów wcześnie w procesie tworzenia aplikacji.
- Samodokumentujący się schemat: Generuje schemat, który można łatwo eksplorować za pomocą narzędzi takich jak GraphiQL. Ułatwia to programistom zrozumienie i korzystanie z API.
- Jedno miejsce do pobierania danych: Dzięki temu podejściu, można uzyskać dostęp do różnych źródeł danych za pomocą pojedynczego punktu końcowego, co ułatwia integrację i zarządzanie różnymi serwisami w naszej aplikacji.
Podsumowanie
W tym artykule omówiliśmy, jak skonfigurować i wykorzystać innowacyjne podejście w aplikacji Symfony z wykorzystaniem API Platform. Zobaczyliśmy, jak automatycznie generowany schemat pozwala na wykonywanie zapytań, które są dostosowane do naszych potrzeb oraz jak korzystać z interfejsu GraphiQL do eksploracji i testowania zapytań. Przedstawiliśmy również korzyści płynące z zastosowania tego podejścia w naszej aplikacji, takie jak elastyczność, silna typizacja i samodokumentujący się schemat.
Pingback: Jak używać GraphQL do bardziej efektywnego pobierania danych w aplikacjach internetowych – YouTalent® Blog Edukacyjny – Polska