Dwa podejścia do komunikacji między frontendem a backendem
Projektując aplikację webową, prędzej czy później stajemy przed pytaniem: jak frontend ma pobierać dane z backendu? Przez lata standardem było REST API. Od 2015 roku, gdy Facebook opublikował specyfikację GraphQL, pojawiła się poważna alternatywa. Oba podejścia mają swoje mocne strony i ograniczenia — kluczem jest zrozumienie, kiedy które sprawdzi się lepiej.
REST API — sprawdzony standard
REST (Representational State Transfer) to styl architektoniczny oparty na zasobach i metodach HTTP. Każdy zasób (użytkownik, produkt, zamówienie) ma swój endpoint, a operacje CRUD mapowane są na metody HTTP:
GET /api/users — lista użytkowników
GET /api/users/42 — szczegóły użytkownika o ID 42
POST /api/users — utworzenie nowego użytkownika
PUT /api/users/42 — aktualizacja użytkownika
DELETE /api/users/42 — usunięcie użytkownika
To intuicyjny model: URL identyfikuje zasób, metoda HTTP określa operację, kody statusu (200, 201, 404, 500) informują o wyniku. REST działa z każdym klientem HTTP — przeglądarką, aplikacją mobilną, narzędziem wiersza poleceń, nawet curl.
Mocne strony REST:
- Prostota — opiera się na standardowych mechanizmach HTTP, które każdy programista zna
- Cache — odpowiedzi GET można cachować za pomocą standardowych nagłówków HTTP (ETag, Cache-Control)
- Narzędzia — ogromny ekosystem: Swagger/OpenAPI do dokumentacji, Postman do testowania, middleware do autoryzacji
- Skalowalność — bezstanowość REST sprawia, że łatwo skalować horyzontalnie (load balancing)
- Dojrzałość — sprawdzony w produkcji przez dekady, dobrze rozumiany przez zespoły
GraphQL — elastyczność zapytań
GraphQL to język zapytań i runtime stworzony przez Facebook. Zamiast wielu endpointów mamy jeden (/graphql), a klient precyzyjnie określa, jakie dane chce otrzymać:
query {
user(id: 42) {
name
email
orders(last: 5) {
id
total
items {
name
price
}
}
}
}
Jedno zapytanie pobiera użytkownika, jego ostatnie 5 zamówień i pozycje w każdym zamówieniu. W REST wymagałoby to 2-7 osobnych zapytań HTTP (użytkownik, zamówienia, pozycje każdego zamówienia) lub stworzenia specjalnego endpointu.
Mocne strony GraphQL:
- Precyzyjne pobieranie danych — klient dostaje dokładnie to, o co prosi, nic więcej (eliminuje over-fetching)
- Jedno zapytanie zamiast wielu — złożone dane z wielu powiązanych zasobów w jednym żądaniu (eliminuje under-fetching)
- Silne typowanie — schemat definiuje dostępne typy, pola i relacje, co daje doskonałą dokumentację i walidację
- Introspection — klient może odpytać serwer o dostępny schemat, co ułatwia eksplorację API
- Ewolucja bez wersjonowania — dodawanie nowych pól nie psuje istniejących klientów, bo każdy klient pyta tylko o to, czego potrzebuje
Problem over-fetching i under-fetching
Te dwa problemy to główna motywacja za GraphQL.
Over-fetching — REST endpoint zwraca więcej danych niż klient potrzebuje. Endpoint /api/users/42 zwraca 30 pól (imię, email, adres, historię, preferencje...), a frontend potrzebuje tylko imienia i avatara. Cały nadmiar jest przesyłany przez sieć i przetwarzany — szczególnie bolesne na wolnych połączeniach mobilnych.
Under-fetching — potrzebujemy danych z wielu zasobów, ale REST wymaga osobnego zapytania na każdy. Strona profilu wymaga danych użytkownika (/api/users/42), jego postów (/api/users/42/posts), znajomych (/api/users/42/friends) i powiadomień (/api/notifications). Cztery zapytania HTTP, każde z osobnym round-tripem do serwera.
GraphQL rozwiązuje oba problemy jednym precyzyjnym zapytaniem. Ale czy to zawsze konieczne?
Kiedy REST jest lepszym wyborem
REST sprawdza się najlepiej, gdy:
- API jest publiczne — REST jest uniwersalnie zrozumiały, łatwy do dokumentowania i testowania. Większość integracji między firmami opiera się na REST
- Operacje są proste — CRUD na kilku zasobach nie wymaga elastyczności GraphQL
- Cache jest ważny — HTTP cache dla REST jest trywialny (GET na URL = klucz cache). W GraphQL wszystkie zapytania to POST na ten sam endpoint, co komplikuje cachowanie
- Zespół jest mały — REST nie wymaga dodatkowej warstwy (serwer GraphQL, schemat, resolwery) i jest szybszy we wdrożeniu
- Serwer renderuje HTML — gdy backend generuje strony HTML (jak w naszych projektach w Go), REST endpoints dla danych zewnętrznych są naturalnym wyborem
Kiedy GraphQL jest lepszym wyborem
GraphQL sprawdza się, gdy:
- Frontend jest złożony — aplikacje SPA (React, Vue) z wieloma widokami potrzebującymi różnych kombinacji danych
- Wielu klientów — aplikacja webowa, mobilna i desktopowa potrzebują tych samych danych, ale w różnych konfiguracjach
- Złożone relacje — dane są mocno powiązane (graf) i różne widoki potrzebują różnych głębokości tych relacji
- Szybka iteracja frontendu — frontend może dodawać i usuwać pola bez zmian w backendzie
- Mikroserwisy — GraphQL może służyć jako warstwa agregacyjna łącząca dane z wielu mikroserwisów
Wady GraphQL, o których się rzadziej mówi
GraphQL nie jest panaceum. Warto znać jego ograniczenia:
- Złożoność serwera — definiowanie schematu, resolverów i optymalizacja zapytań (problem N+1) wymaga dodatkowej pracy
- Trudniejsze cachowanie — brak standardowego HTTP cache wymusza użycie bibliotek (Apollo Client) lub CDN ze wsparciem dla GraphQL
- Bezpieczeństwo — klient może tworzyć dowolnie głębokie i kosztowne zapytania. Potrzebne są limity głębokości, złożoności i rate limiting
- Monitoring — wszystkie żądania to POST na
/graphql, co utrudnia analizę logów i monitorowanie poszczególnych operacji - Przesyłanie plików — GraphQL nie ma natywnego wsparcia dla upload plików, wymagane są obejścia (multipart lub osobny endpoint REST)
Podejście hybrydowe
W praktyce wiele projektów łączy oba podejścia. REST dla prostych operacji CRUD i integracji zewnętrznych, GraphQL dla złożonych widoków frontendowych wymagających elastyczności. To pragmatyczne rozwiązanie, które wykorzystuje mocne strony obu technologii.
Inną opcją wartą rozważenia jest tRPC (dla projektów w TypeScript) lub proste REST z dobrze zaprojektowanymi endpointami, które zwracają zagnieżdżone dane tam, gdzie to potrzebne. Czasem wystarczy dodać parametr ?include=orders,items do REST endpoint, zamiast wdrażać cały stos GraphQL.
Podsumowanie
REST API to sprawdzony, prosty i uniwersalny standard, który sprawdza się w większości projektów — szczególnie w małych i średnich aplikacjach, publicznych API i projektach z server-side rendering. GraphQL to potężne narzędzie dla złożonych frontendów z wieloma klientami i skomplikowanymi relacjami danych, ale niesie ze sobą dodatkową złożoność.
Wybór powinien wynikać z realnych potrzeb projektu, a nie z trendów. Jeśli REST z dobrze zaprojektowanymi endpointami rozwiązuje Twoje problemy — to jest właściwy wybór. Jeśli walczysz z over-fetchingiem, mnożącymi się endpointami i różnymi potrzebami wielu klientów — GraphQL może znacząco uprościć architekturę.