Sześć styli API w porównaniu: REST, GraphQL, WebSockets, Webhooks, gRPC, SOAP
Dowiedz się, w jaki sposób REST, GraphQL, WebSockets, webhooks, gRPC i SOAP rozwiązują różne problemy związane ze wymianą danych, a także zapoznaj się z mapą decyzyjną pomagającą wybrać odpowiednią technologię.
Większość ludzi wybiera REST jako swój pierwszy styl API i potem traktuje go jak uniwersalne rozwiązanie. Tak nie jest. REST to zaledwie jedna z sześciu opcji, a pozostałe pięć istnieje właśnie dlatego, że REST napotyka poważne ograniczenia w określonych sytuacjach — aktualizacje na żywo, szybkie wewnętrzne połączenia między usługami, ścisłe wymagania bezpieczeństwa w przedsiębiorstwach oraz elastyczna struktura danych. Każdy inny styl API na tej liście został stworzony, aby radzić sobie z tym, z czym ma trudności REST.
Jeśli REST jest już dla ciebie znajomym tematem, to, co następuje, precyzyjnie określi, kiedy powinieneś zmienić narzędzia i dlaczego.
Czym jest API (jeden akapit, a potem idziemy dalej)
W istocie API pełni rolę pośrednika pomiędzy dwoma systemami, umożliwiając im komunikację. Gdy wpisujesz „biryani” do aplikacji dostawy jedzenia, wyniki nie są już przechowywane na twoim telefonie. Twoja aplikacja wysyła żądanie do serwera firmy, a serwer odpowiada odpowiednimi danymi. Zasady rządzące tą wymianą – sposób tworzenia żądania, wygląd odpowiedzi – to właśnie API. Wyobraź sobie kelnera w restauracji: nigdy nie idziesz do kuchni po swoje jedzenie; mówisz kelnerowi, czego chcesz, a on zajmuje się resztą. Ten kelner jest w zasadzie API.
REST: Standard i jego ograniczenia
REST, skrót od Representational State Transfer, działa na bazie HTTP i opiera się na dwóch kluczowych koncepcjach: adresie URL identyfikującym zasób, którego chcesz użyć, oraz metodzie HTTP opisującej działanie, które chcesz na nim wykonać.
Cztery metody obejmują praktycznie wszystko: GET pobiera dane, POST tworzy nowy rekord, PUT aktualizuje lub zastępuje istniejący, a DELETE go usuwa. Kluczową cechą REST jest brak stanu – serwer nie przechowuje żadnych informacji o poprzednich interakcjach z użytkownikiem. Wszystkie niezbędne dane muszą być zawarte w samej prośbie, za każdym razem.
GET https://api.zomato.com/v1/restaurants?search=biryani
Authorization: Bearer <token>
Gdy prośba dotrze na serwer, ten weryfikuje tożsamość użytkownika, pobiera odpowiednie rekordy z bazy danych i wysyła z powrotem treść w formacie JSON.
Gdzie się sprawdza: interfejsy API dostępne dla publiczności, standardowe aplikacje do tworzenia, odczytu, aktualizacji i usuwania danych oraz wszelkie scenariusze, w których klient i serwer są wyraźnie oddzielone i wymagają przewidywalnego, dobrze udokumentowanego kontraktu. REST zasłużył na swój standardowy status z dobrego powodu — jest prosty, nie wymaga od serwera śledzenia stanu sesji, jest powszechnie rozumiany i opiera się na zwykłym HTTP.
Gdzie ma wady: wszystko, co wymaga aktualizacji w czasie rzeczywistym (aplikacje czatowe, śledzenie lokalizacji w czasie rzeczywistym), przypadki, gdy jedno ekran potrzebuje danych pobranych jednocześnie z kilku różnych źródeł, lub komunikacja między usługami wewnętrznymi, gdzie surowa szybkość przeważa nad czytelnością dla człowieka.
GraphQL: Proś o dokładnie to, czego potrzebujesz
REST boryka się z dobrze znanym problemem: nadmiernego pobierania danych. Jeśli wywołasz endpoint /user, możesz otrzymać imię, zdjęcie profilowe, wiek, dział, pensję oraz tuzin innych pól — mimo że tak naprawdę chciałeś tylko imię i zdjęcie. Drugim problemem jest niewystarczające pobieranie danych, gdy jedna widok musi korzystać z informacji z kilku zasobów, co zmusza do wysłania kilku żądań REST i połączenia wyników na stronie klienta.
GraphQL rozwiązuje oba te problemy jednocześnie: jeden endpoint w połączeniu z językiem zapytań, który pozwala klientowi dokładnie określić, które pola chce otrzymać.
# Instead of hitting /employees/123 and getting everything,
# you describe precisely what you need in the request body
query {
employee(id: "123") {
name
photo
}
}
Odpowiedź zawiera tylko te dwa wymagane pola — nic więcej. Potrzebujesz też informacji o pensji? Po prostu dodaj ją do zapytania. Nie ma potrzeby tworzenia oddzielnego endpointu w tym celu.
GraphQL obsługuje trzy rodzaje operacji. Zapytanie odczytuje dane i pełni tę samą funkcję co REST GET. Mutacja zapisuje lub modyfikuje dane, odpowiadając połączeniu POST, PUT i DELETE. Subskrypcja otwiera strumień danych w czasie rzeczywistym umożliwiający ciągłe aktualizacje i funkcjonuje w podobny sposób jak WebSockets.
Gdzie się sprawdza: zaawansowane interfejsy użytkownika wymagające elastycznych struktur danych, aplikacje mobilne, w których ważna jest minimalizacja rozmiaru przesyłanych danych, oraz wszelkie sytuacje, w których różne typy klientów — internetowe, mobilne, integracje z podmiotami trzecimi — korzystają z tego samego backendu, ale każdy potrzebuje innego fragmentu danych.
Gdzie odbiega od standardu: podstawowe usługi CRUD, w których proste punkty końcowe REST już dobrze spełniają swoje zadanie. GraphQL wprowadza prawdziwą złożoność po stronie serwera, cache staje się znacznie trudniejszy w zarządzaniu niż w przypadku REST, a jego użycie jest często niepotrzebnym obciążeniem, gdy potrzeby przetwarzania danych są stabilne i dobrze określone.
WebSockets: Trwałe połączenie
Funkcje w czasie rzeczywistym ujawniają fundamentalną słabość REST. Aby dowiedzieć się, czy właśnie nadeszła nowa wiadomość w czacie, klient oparty na REST musiałby ciągle sprawdzać: „Czy coś nowego?”, „Czy coś nowego?” – w kółko. Gdy mnożymy to przez milion jednoczesnych użytkowników, otrzymujemy milion zapytań na sekundę, przy czym zdecydowana większość z nich odpowiada „nie”, co stanowi czystą stratę zasobów.
WebSockets całkowicie unikają tego problemu, zastępując wzorzec żądanie-odpowiedź trwałym, dwukierunkowym połączeniem. Zaczyna się jako zwykłe żądanie HTTP, ale zawiera specjalny nagłówek upgrade:
GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Gdy serwer to przyjmuje, to połączenie HTTP przekształca się w połączenie WebSocket. Od tego momentu każda ze stron może wysyłać wiadomości do drugiej w dowolnym momencie, bez konieczności uprzedniego proszenia o zgodę. Kanał pozostaje otwarty, dopóki jedna ze stron celowo go nie zamknie.
Połączenie WebSocket przechodzi przez cztery odrębne stany: Connecting (trwa nawiązywanie połączenia), Open (przesyłane są wiadomości w obu kierunkach), Closing (rozpoczęto zamykanie połączenia) oraz Closed (połączenie już nie istnieje). Próba wysłania danych przez już zamknięte połączenie spowoduje awarię serwera – to błąd, z którym często borykają się początkujący.
Gdzie się to stosuje: czat na żywo, gry wieloosobowe, narzędzia do wspólnej edycji w czasie rzeczywistym takie jak udostępniane dokumenty, aktualne wyniki sportowe oraz powiadomienia typu push – zasadniczo we wszystkich przypadkach, gdy serwer musi wysyłać dane bez żadnego wyzwalacza.
Gdzie odbiegają od standardu: przy zwykłym pobieraniu danych, gdy klient potrzebuje informacji tylko wtedy, gdy o nie wyraźnie prosi. Ponieważ WebSockets utrzymują połączenia otwarte przez cały czas, zużywają zasoby serwera. Ich stosowanie tam, gdzie wystarczyłby zwykły REST, to jedynie marnotrawstwo zasobów bez żadnej korzyści.
Webhooks: Serwer do Ciebie dzwoni
Zarówno REST, jak i WebSockets zaczynają się od klienta – to on nawiązuje połączenie, wysyła żądanie, a serwer odpowiada. Webhooks całkowicie odwracają ten proces – zamiast Ty prosić serwer o aktualizacje, serwer kontaktuje się z Tobą w momencie, gdy dzieje się coś, o czym warto wiedzieć.
Mechanizm jest prosty. Rejestrujesz adres URL w jakiejś usłudze third-party i określasz, co ma się z tym adresem URL dziać: na przykład „gdy płatność zostanie sfinalizowana, wyślij tutaj żądanie POST”. W momencie, gdy płatność faktycznie zostanie przetworzona, dostawca płatności — Razorpay, Stripe lub ktokolwiek inny, którego używasz — automatycznie wysyła żądanie do twojego punktu końcowego. Nie ma żadnego pętla pollingu, nie trzeba pilnować połączenia. Po prostu czekasz, aż nadejdzie wezwanie.
# What you give Razorpay in setup:
Webhook URL: https://yourapp.com/webhooks/payment
# What Razorpay sends when payment completes:
POST https://yourapp.com/webhooks/payment
{
"event": "payment.captured",
"payload": { "amount": 50000, "order_id": "order_abc" },
"signature": "sha256_hash_here"
}
Weryfikacja podpisu nie jest tu opcjonalna — stanowi całkowitą ochronę. Twój endpoint webhook jest dostępny publicznie, co oznacza, że teoretycznie każdy może wysłać fałszywe zdarzenie „payment.captured” i oszukać twój system, aby ten zwolnił zamówienie, za które w rzeczywistości nie zapłacono. Podpis zawarty w treści wiadomości to hasz kryptograficzny, który potwierdza, że żądanie rzeczywiście pochodzi od dostawcy. Twój serwer musi sprawdzić ten podpis, zanim podejmie jakiekolwiek działania na podstawie treści żądania.
Kiedy go używać: przy potwierdzeniach płatności, zmianach statusu zamówień, w pipeline’ach CI/CD (GitHub powiadamia twój serwer za każdym razem, gdy trafia nowy kod) oraz ogólnie w dowolnym procesie pracy, w którym reagujesz na zdarzenie wystąpiłece w jakimś zewnętrznym systemie.
Kiedy nie należy go używać: w przypadku czegokolwiek, co wymaga natychmiastowej odpowiedzi w ramach tej samej interakcji z użytkownikiem. Webhooki działają w czasie późniejszym — są z natury asynchroniczne. Gdy użytkownik siedzi przed ekranem i czeka na potwierdzenie, REST pozostaje lepszym rozwiązaniem.
gRPC: szybkość binarna dla usług wewnętrznych
Zazwyczaj duża aplikacja to nie jeden serwer. Na przykład platforma taka jak Zomato uruchamia oddzielne usługi do obsługi zamówień, płatności, powiadomień oraz danych o restauracjach, a usługi te wywołują się nawzajem tysiące razy na sekundę. Jeśli cała ta wewnętrzna komunikacja odbywa się przez REST, konieczne jest ciągłe serializowanie i deserializowanie danych w formacie JSON. Łatwość odczytu JSON jest przydatna dla programisty analizującego logi, ale ta sama łatwość wiąże się z wysokimi kosztami przetwarzania, gdy ilość danych rośnie.
gRPC, pierwotnie stworzony przez Google do obsługi własnego ruchu wewnętrznego, zastępuje JSON formatem Protocol Buffers (Protobuf) – binarnym formacie, który jest znacznie bardziej kompaktowy i szybszy do kodowania oraz dekodowania. Dokładnie ten sam ciężar danych, który REST wysyłałby w postaci tekstu czytelnego, jest przez gRPC przesyłany jako gęsty binarny obiekt, który maszyny mogą przetwarzać o wiele szybciej.
// You define your data structure once in a .proto file
message OrderRequest {
string order_id = 1;
string user_id = 2;
float amount = 3;
}
Zysk wydajności nie wynika tylko z formatu danych. gRPC działa również na bazie HTTP/2, co umożliwia multiplexing – tysiące żądań może być przesyłanych jednocześnie przez jeden wspólny połączenie, w odróżnieniu od HTTP/1.1, który przetwarza je po jednym. Ponadto gRPC oferuje cztery różne wzorce komunikacji: Unary (jedno żądanie połączone z jedną odpowiedzią, o tej samej strukturze co REST), Server Streaming (jedno żądanie, które uruchamia strumień odpowiedzi, przydatne na przykład do śledzenia zamówień w czasie rzeczywistym), Client Streaming (wiele żądań łączonych w jedną końcową odpowiedź, użyteczne przy przesyłaniu pliku w częściach) oraz Bidirectional Streaming (obie strony przesyłają dane do siebie w sposób ciągły, co nadaje się do funkcji współpracy w czasie rzeczywistym).
Kiedy go używać: przy ruchu między usługami w ramach własnej infrastruktury, gdzie ważna jest szybkość oraz ścisła typizacja. Wszędzie tam, gdzie usługi wymieniają duże ilości żądań, a analiza JSON staje się istotnym kosztem.
Kiedy go nie używać: w API skierowanych do publiczności, wykorzystywanych przez przeglądarki lub deweloperów z zewnątrz. Binarny charakter Protobuf utrudnia jego inspekcję i debugowanie, a uruchomienie go w przeglądarce wymaga dodatkowych ustawień. Dla wszystkiego, co skierowane do użytkowników końcowych, REST pozostaje bardziej praktycznym wyborem.
SOAP: Ścisły, rozbudowany i nadal używany w bankach
SOAP (Simple Object Access Protocol) pochodzi z 1998 roku, co czyni go starszym od samego REST. Większość deweloperów spotyka się z nim obecnie jedynie podczas łączenia się z systemami bankowymi, platformami ubezpieczeniowymi lub dużym oprogramowaniem korporacyjnym — branżami, które wcześnie przyjęły SOAP i nigdy nie miały poważnego powodu, by od niego odejść.
SOAP nie daje się dostosować. Każda wiadomość to XML zapakowany w ściśle określony kontener. Podczas gdy REST pozostawia dużo swobody w kształtowaniu danych, SOAP wymaga, aby obie strony przestrzegały dokładnego, z góry określonego schematu.
<!-- Every SOAP message follows this envelope structure -->
<Envelope>
<Header>
<Security><!-- authentication goes here --></Security>
</Header>
<Body>
<GetAccountBalance>
<AccountId>ACC123</AccountId>
</GetAccountBalance>
</Body>
</Envelope>
Ta ciężka struktura istnieje celowo. Standard WS-Security w SOAP łączy autoryzację, podpisy cyfrowe i szyfrowanie w jednej wiadomości. W przypadku transakcji finansowych, gdzie jakiekolwiek ingerencje w trakcie przesyłania mogą spowodować poważne szkody, ta wbudowana warstwa ochrony usprawiedliwia dodatkową objętość.
Kiedy go używać: podczas łączenia się z API banku, bramką płatniczą wymagającą SOAP, systemami rządowymi, platformami ubezpieczeniowymi lub dowolnym starszym systemem korporacyjnym, który udostępnia jedynie interfejs SOAP. Raczej nie wybierzesz SOAP do projektu budowanego od zera, ale jego zrozumienie jest ważne, gdy musisz współpracować z systemami opartymi na tym standardzie.
Kiedy go nie używać: w nowych projektach, gdzie kontrolujesz obie strony komunikacji. Implementacja SOAP zajmuje więcej czasu, jego pliki XML utrudniają debugowanie, a w porównaniu z REST lub gRPC nie oferuje żadnych zalet, gdy kompatybilność ze starszymi systemami nie jest ograniczeniem.
Mapa decyzji
Użyj tego jako szybkiego przewodnika do wyboru odpowiedniego narzędzia:
Standardowa aplikacja internetowa lub API dostępne dla publiczności wykorzystuje REST. Aplikacja mobilna, która wymaga elastycznych danych dostosowanych do konkretnych potrzeb, korzysta z GraphQL. Rozmowy na żywo, interakcje wieloosobowe lub powiadomienia push w czasie rzeczywistym wymagają WebSockets. Potwierdzenia płatności oraz mechanizmy uruchamiania procesów CI/CD wykorzystują Webhooks. Wewnętrzne mikrosługi wymagające wysokiej wydajności korzystają z gRPC. Systemy bankowe oraz integracje z starszymi systemami przedsiębiorstw wykorzystują SOAP.
To, co teraz rozumiesz
REST pozostaje standardowym wyborem. Wszystkie inne wzory istnieją po to, by zaadresować konkretne braki, w których REST zawodzi: GraphQL przydaje się, gdy potrzeby danych różnią się w zależności od klienta; WebSockets, gdy połączenie musi pozostać otwarte w obu kierunkach; Webhooks, gdy chcemy reagować na zdarzenia zamiast ciągle o nie pytać; gRPC, gdy JSON staje się zbyt wolne dla ruchu wewnętrznego serwisu; a SOAP, gdy wymagania bezpieczeństwa na poziomie przedsiębiorstwa nie pozostawiają innej opcji.
Następnym razem, gdy projektujesz integrację, nie zaczynaj od pytania, jak przymusić użycie REST. Zamiast tego zapytaj, który wzór komunikacji faktycznie odpowiada temu, co system musi robić. To odpowiedź powinna decydować o wyborze narzędzia, a nie nawyk.
Jako następny krok wybierz jeden z tych wzorców, z którymi jeszcze nie pracowałeś. Znajdź jego oficjalną dokumentację lub mały projekt open-source oparty na nim i przeczytaj rzeczywistą implementację, zanim będziesz zmuszony stworzyć ją pod presją.