REST API – co to jest, jak działa i jak je projektować?

Co to jest REST API?

REST (Representational State Transfer) to styl architektoniczny wykorzystywany do projektowania systemów rozproszonych, w szczególności interfejsów API umożliwiających komunikację pomiędzy aplikacjami. Został opisany w 2000 roku przez Roya Fieldinga w jego rozprawie doktorskiej na Uniwersytecie Kalifornijskim w Irvine.

REST nie jest protokołem ani technologią, lecz zbiorem zasad architektonicznych określających, w jaki sposób powinny komunikować się ze sobą komponenty systemu.

REST API to z koleji interfejs programistyczny zaprojektowany, aby umożlwić wymianę informacji oraz wykonywanie operacji na zasobach udostępnianych przez serwer. W praktyce REST API najczęściej wykorzystuje protokół HTTP, a dane przesyłane są w formacie JSON.

Podstawowe zasady architektury REST

Architektura REST opiera się na kilku fundamentalnych zasadach:

  • Client–Server – rozdzielenie odpowiedzialności pomiędzy klientem a serwerem. Klient odpowiada za interfejs użytkownika, natomiast serwer za przetwarzanie żądań i udostępnianie zasobów.
  • Stateless (bezstanowość) – każde żądanie powinno zawierać wszystkie informacje niezbędne do jego obsłużenia. Serwer nie przechowuje kontekstu sesji klienta pomiędzy żądaniami.
  • Cacheable (buforowanie) – odpowiedzi serwera powinny określać, czy mogą być przechowywane w pamięci podręcznej, co pozwala ograniczyć liczbę żądań i poprawić wydajność.
  • Uniform Interface (jednolity interfejs) – komunikacja pomiędzy komponentami odbywa się według spójnych zasad, niezależnie od ich implementacji.
  • Layered System (system warstwowy) – architektura może składać się z wielu warstw pośredniczących, takich jak serwery proxy, bramy API czy load balancery.

REST a HTTP?

REST a HTTP to dwie różne rzeczy. HTTP (Hypertext Transfer Protocol) to protokół komunikacyjny definiujący sposób przesyłania żądań i odpowiedzi pomiędzy klientem a serwerem. Natomiast REST określa zasady architektoniczne, według których taka komunikacja powinna być zaprojektowana.

Jak działa REST API?

Jak już wspomniałem komunikacja w REST API opiera się najczęściej na modelu klient–serwer. Klient wysyła żądanie (request) HTTP do serwera, który przetwarza je, wykonuje odpowiednią operację i zwraca odpowiedź (response). Klientem może być aplikacja internetowa, aplikacja mobilna lub inny system. Serwer natomiast udostępnia zasoby i odpowiada za ich przetwarzanie.

Mechanizm Request–Response

Komunikację z REST API można przedstawić na przykładzie pobierania informacji o produkcie ze sklepu internetowego.

1. Klient wysyła żądanie HTTP

GET /api/products/10 HTTP/1.1 
Host: api.example.com 
Accept: application/json

W żądaniu znajdują się:

  • Metoda HTTP (GET) – określa rodzaj operacji, którą klient chce wykonać.
  • URI (/api/products/10) – wskazuje zasób, którego dotyczy żądanie.
  • Nagłówki (Headers) – przekazują dodatkowe informacje, np. oczekiwany format odpowiedzi.

2. Serwer przetwarza żądanie

3. Serwer zwraca odpowiedź HTTP

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 10,
  "name": "Laptop",
  "price": 3500.00,
  "currency": "PLN"
}

Odpowiedź zawiera:

  • Status HTTP – informuje o wyniku operacji, w tym przypadku jest to status OK (o numerze 200).
  • Nagłówki odpowiedzi – określają m.in. format zwracanych danych.
  • Response Body – zawiera reprezentację zasobu, w tym przypadku w formacie JSON.

Jeżeli produkt o wskazanym identyfikatorze nie istnieje, serwer może zwrócić inna odpowiedź (np. o błędzie).

Bezstanowość (Stateless)

Jedną z najważniejszych cech REST jest bezstanowość komunikacji. Oznacza to, że każde żądanie klienta powinno zawierać wszystkie informacje niezbędne do jego obsłużenia, bez konieczności odwoływania się do kontekstu poprzednich żądań.

Metody HTTP w REST API

Protokół HTTP udostępnia zestaw metod określających rodzaj operacji, jaką klient może wykonać na zasobie serwera. W REST API najczęściej wykorzystuje się pięć podstawowych metod: GET, POST, PUT, PATCH oraz DELETE. Postaram się teraz je tutaj omówić.

GET – pobieranie danych

Metoda GET służy do pobierania reprezentacji zasobów z serwera. Nie powinna powodować zmian ich stanu.

Przykładowo, aby pobrać listę produktów ze sklepu internetowego, można wykonać żądanie:

GET /api/products

Natomiast pobranie konkretnego produktu o identyfikatorze 10 będzie wyglądało następująco:

GET /api/products/10

Serwer zwróci odpowiedź zawierającą dane produktu, zazwyczaj w formacie JSON.

Metoda GET jest bezpieczna (Safe) oraz idempotentna (Idempotent). Oznacza to, że jej wywołanie nie powinno modyfikować zasobu, a wielokrotne wykonanie identycznego żądania ma taki sam zamierzony efekt jak pojedyncze wywołanie.

POST – tworzenie zasobów

Metoda POST służy do przesyłania danych do serwera w celu ich przetworzenia. W REST API najczęściej wykorzystuje się ją do tworzenia nowych zasobów.

Przykład dodania produktu:

POST /api/products
Content-Type: application/json

{
  "name": "Laptop",
  "price": 3500.00
}

Serwer przetwarza przesłane dane i tworzy nowy produkt. W przypadku powodzenia powinien zazwyczaj zwrócić status 201 Created oraz może wskazać adres utworzonego zasobu za pomocą nagłówka Location.

HTTP/1.1 201 Created
Location: /api/products/10

Metoda POST nie jest domyślnie idempotentna. Dwukrotne wysłanie identycznego żądania może przykładowo spowodować utworzenie dwóch różnych produktów.

PUT – zastępowanie zasobów

Metoda PUT służy do utworzenia lub zastąpienia stanu zasobu pod wskazanym adresem URI.

Przykładowo, aby zastąpić dane produktu o identyfikatorze 10, można wysłać żądanie:

PUT /api/products/10
Content-Type: application/json

{
  "name": "Laptop Dell",
  "price": 4000.00
}

W odróżnieniu od PATCH, PUT służy do przekazania docelowego stanu zasobu, a nie jedynie instrukcji zmiany wybranych pól. W praktyce oznacza to, że pominięcie niektórych właściwości może skutkować ich usunięciem, przywróceniem wartości domyślnych lub odrzuceniem żądania, zależnie od kontraktu API.

PUT jest metodą idempotentną. Wielokrotne wykonanie identycznego żądania powinno prowadzić do tego samego docelowego stanu zasobu.

PATCH – częściowa aktualizacja zasobów

Metoda PATCH służy do wprowadzania częściowych zmian w istniejącym zasobie.

Przykładowe żądanie wykorzystujące format JSON Merge Patch:

PATCH /api/products/10
Content-Type: application/merge-patch+json

{
  "price": 4200.00
}

W tym przypadku zmodyfikowana zostanie jedynie cena produktu.

Najważniejsza różnica między PUT a PATCH polega na tym, że PUT określa docelową reprezentację zasobu, natomiast PATCH opisuje zmiany, które należy w nim wprowadzić.

PATCH nie jest z definicji idempotentny, chociaż konkretna operacja może spełniać tę właściwość.

Przykładowo, ustawienie ceny produktu na 4200 PLN jest idempotentne, natomiast operacja polegająca na zwiększeniu ceny o 100 PLN przy każdym wywołaniu już nie.

DELETE – usuwanie zasobów

Metoda DELETE służy do usuwania powiązania wskazanego zasobu z jego adresem URI. W praktycznych REST API najczęściej oznacza usunięcie zasobu.

Przykładowo:

DELETE /api/products/10

Serwer usuwa wskazany produkt i może zwrócić odpowiedź:

HTTP/1.1 204 No Content

Metoda DELETE jest idempotentna. Usunięcie tego samego zasobu kilkukrotnie powinno mieć taki sam końcowy efekt jak pojedyncze usunięcie.

Nie oznacza to jednak, że każde wywołanie musi zwracać identyczny kod HTTP. Pierwsze żądanie może zakończyć się statusem 204 No Content, a kolejne 404 Not Found, ponieważ zasób już nie istnieje.

Kody odpowiedzi HTTP

Każde żądanie HTTP wysłane do serwera kończy się odpowiedzią zawierającą kod statusu HTTP (HTTP Status Code). Jest to trzycyfrowa liczba informująca klienta o wyniku przetwarzania żądania.

Kody odpowiedzi HTTP dzielą się na pięć podstawowych kategorii:

KategoriaZnaczenie
1xxInformacje o przebiegu komunikacji
2xxŻądanie zakończone sukcesem
3xxPrzekierowania i inne działania wymagane do obsługi żądania
4xxBłędy związane z żądaniem klienta
5xxBłędy po stronie serwera

Poprawne wykorzystanie kodów HTTP jest jednym z fundamentów projektowania REST API. Dzięki nim klient może rozpoznać, czy operacja zakończyła się powodzeniem, czy wystąpił błąd oraz jak powinien na niego zareagować.

1xx – odpowiedzi informacyjne

Kody z grupy 1xx oznaczają, że serwer otrzymał żądanie, ale komunikacja nie została jeszcze zakończona. Są to odpowiedzi tymczasowe, po których zazwyczaj następuje odpowiedź końcowa.

Najważniejsze przykłady:

  • 100 Continue – serwer informuje klienta, że może kontynuować przesyłanie treści żądania.
  • 101 Switching Protocols – serwer potwierdza zmianę protokołu komunikacyjnego, np. podczas przechodzenia z HTTP/1.1 do WebSocket

W codziennej pracy z REST API programista stosunkowo rzadko musi bezpośrednio obsługiwać te kody.

2xx – poprawne wykonanie żądania

Kody z grupy 2xx informują, że żądanie zostało pomyślnie obsłużone.

Najczęściej wykorzystywane statusy to:

KodNazwaZastosowanie
200OKOperacja zakończona sukcesem, np. pobranie produktu
201CreatedUtworzono nowy zasób
202AcceptedPrzyjęto żądanie do przetwarzania, ale operacja nie została jeszcze zakończona
204No ContentOperacja zakończona sukcesem, bez zwracania treści odpowiedzi

Przykładowo, pobranie produktu za pomocą metody GET może zakończyć się odpowiedzią:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 10,
  "name": "Laptop",
  "price": 3500.00
}

Z kolei utworzenie nowego produktu za pomocą metody POST powinno zazwyczaj zwrócić status 201 Created wraz z adresem utworzonego zasobu:

HTTP/1.1 201 Created
Location: /api/products/10

W przypadku usuwania produktu często wykorzystuje się 204 No Content, ponieważ klient nie musi otrzymywać dodatkowych danych.

Warto również zwrócić uwagę na 202 Accepted, który jest szczególnie przydatny w systemach wykorzystujących komunikację asynchroniczną. Przykładowo API może przyjąć żądanie wygenerowania raportu, przekazać zadanie do kolejki i natychmiast zwrócić status 202, nie czekając na zakończenie generowania.

3xx – przekierowania

Kody z grupy 3xx informują klienta, że do obsłużenia żądania konieczne może być wykonanie dodatkowej czynności, najczęściej skorzystanie z innego adresu URL.

Najważniejsze przykłady:

  • 301 Moved Permanently – zasób został trwale przeniesiony pod inny adres.
  • 302 Found – zasób jest tymczasowo dostępny pod innym adresem.
  • 304 Not Modified – reprezentacja zasobu nie została zmodyfikowana względem wersji wskazanej przez klienta, dzięki czemu może on wykorzystać wcześniej pobrane dane z pamięci podręcznej.

4xx – błędy klienta

Kody z grupy 4xx oznaczają, że serwer nie może zrealizować żądania z przyczyn związanych z samym żądaniem lub uprawnieniami klienta.

KodNazwaZastosowanie
400Bad RequestNieprawidłowe żądanie, np. błędna składnia JSON
401UnauthorizedBrak poprawnego uwierzytelnienia
403ForbiddenBrak uprawnień do wykonania operacji
404Not FoundNie znaleziono wskazanego zasobu
405Method Not AllowedMetoda HTTP nie jest obsługiwana dla danego zasobu
409ConflictKonflikt z aktualnym stanem zasobu
415Unsupported Media TypeNieobsługiwany format przesłanych danych
422Unprocessable ContentPoprawna składnia żądania, ale niemożliwe przetworzenie jego zawartości
429Too Many RequestsPrzekroczono dopuszczalny limit żądań

Szczególnie istotne jest rozróżnienie pomiędzy 401 Unauthorized a 403 Forbidden.

  • 401 Unauthorized – klient nie został poprawnie uwierzytelniony, np. nie przesłał wymaganego tokenu.
  • 403 Forbidden – serwer odmawia dostępu do zasobu, np. uwierzytelniony użytkownik nie ma odpowiednich uprawnień.

Warto również rozróżniać błędy 400 Bad Request i 422 Unprocessable Content. Pierwszy jest ogólnym statusem nieprawidłowego żądania, natomiast drugi pozwala precyzyjniej wskazać problem z przetworzeniem poprawnie sformułowanej treści.

Przykładowo, próba dodania produktu z ujemną ceną może zakończyć się odpowiedzią:

HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json

{
  "type": "about:blank",
  "title": "Unprocessable Content",
  "status": 422,
  "detail": "Cena produktu nie może być ujemna."
}

Przedstawiony format błędu jest zgodny z koncepcją Problem Details, zdefiniowaną w RFC 9457, która umożliwia ujednolicenie odpowiedzi błędów w HTTP API.

5xx – błędy serwera

Kody z grupy 5xx informują, że serwer nie był w stanie poprawnie obsłużyć żądania.

Najważniejsze przykłady:

KodNazwaZastosowanie
500Internal Server ErrorNieoczekiwany błąd podczas przetwarzania żądania
502Bad GatewaySerwer pośredniczący otrzymał nieprawidłową odpowiedź od innego serwera
503Service UnavailableUsługa jest tymczasowo niedostępna
504Gateway TimeoutSerwer pośredniczący nie otrzymał odpowiedzi od innej usługi w wymaganym czasie

W architekturze mikroserwisowej szczególnie często spotyka się błędy 502 Bad Gateway, 503 Service Unavailable oraz 504 Gateway Timeout, ponieważ komunikacja pomiędzy usługami może przebiegać przez API Gateway, reverse proxy lub load balancer.

Przykładowo, jeżeli API Gateway nie otrzyma odpowiedzi od mikroserwisu odpowiedzialnego za zamówienia w określonym czasie, może zwrócić klientowi status 504 Gateway Timeout.

Warto pamiętać, że odpowiedź 500 Internal Server Error nie powinna zawierać szczegółowych informacji o implementacji aplikacji, takich jak stack trace, zapytania SQL czy dane konfiguracyjne.

Jak dobierać właściwe kody HTTP?

Jednym z częstych błędów podczas projektowania REST API jest zwracanie kodu 200 OK niezależnie od faktycznego wyniku operacji, a następnie umieszczanie informacji o błędzie wyłącznie w treści odpowiedzi.

Takie rozwiązanie jest nieprawidłowe z punktu widzenia semantyki HTTP, ponieważ kod 200 informuje o sukcesie, mimo że żądana operacja nie została zrealizowana.

Poprawniejszym rozwiązaniem będzie zwrócenie statusu 404 Not Found wraz z opcjonalnym opisem błędu.

Format danych i komunikacja w REST API

Komunikacja pomiędzy klientem a serwerem w REST API polega na wymianie żądań i odpowiedzi HTTP. Oprócz metod HTTP i kodów odpowiedzi istotną rolę odgrywają format przesyłanych danych, nagłówki HTTP (Headers) oraz treść wiadomości (Body).

REST nie narzuca konkretnego formatu danych. W praktyce najczęściej wykorzystywany jest JSON, ale możliwe są też inne formaty danych: XML, HTML czy jako zwykły tekst

JSON (JavaScript Object Notation) to lekki, tekstowy format wymiany danych, który jest czytelny zarówno dla człowieka, jak i dla maszyny. Wbrew nazwie nie dotyczy on tylko i wyłącznie JavaScript.

Przykład:

{
  "id": 10,
  "name": "Laptop Dell",
  "price": 3500.00,
  "available": true,
  "categories": ["Electronics", "Computers"],
  "manufacturer": {
    "id": 5,
    "name": "Dell"
  }
}

JSON obsługuje następujące typy danych:

  • String – ciągi znaków, np. "Laptop Dell".
  • Number – liczby, np. 3500.00.
  • Boolean – wartości logiczne true i false.
  • Null – brak wartości.
  • Array – tablice elementów, np. ["Electronics", "Computers"].
  • Object – obiekty zawierające pary klucz–wartość.

Request Body i Response Body

Treść wiadomości HTTP (Body) służy do przesyłania danych pomiędzy klientem a serwerem.

Request Body to dane przesyłane przez klienta do serwera. Najczęściej występują w żądaniach POST, PUT i PATCH, np. podczas tworzenia lub aktualizowania zasobu.

Response Body to dane zwracane przez serwer w odpowiedzi na żądanie klienta.

Nie każda odpowiedźmusi zawierać Response Body. Zależy to od logiki zapytania.

Nagłówki HTTP służą do przekazywania dodatkowych informacji dotyczących żądania lub odpowiedzi. Pozwalają określić między innymi format danych, sposób uwierzytelniania, zasady buforowania oraz preferencje klienta.

Najczęściej spotykane:

NagłówekZastosowanie
Content-TypeOkreśla format przesyłanej treści
AcceptOkreśla format odpowiedzi akceptowany przez klienta
AuthorizationPrzekazuje dane uwierzytelniające, np. token
Cache-ControlOkreśla zasady buforowania odpowiedzi
LocationWskazuje adres zasobu, np. po jego utworzeniu
ETagIdentyfikuje konkretną wersję reprezentacji zasobu
If-None-MatchUmożliwia warunkowe pobieranie danych na podstawie ETag

Dobre praktyki projektowania REST API

Poniżej przedstawiam najważniejsze dobre praktyki, które warto stosować podczas projektowania REST API.

1. Stosuj czytelne nazewnictwo endpointów

Adresy URI powinny jednoznacznie identyfikować zasoby. Dobrą praktyką jest wykorzystywanie rzeczowników zamiast czasowników, ponieważ rodzaj wykonywanej operacji określa już metoda HTTP.

Przykładowo:

NiepoprawneZalecane
GET /getProductsGET /products
GET /getProduct/10GET /products/10
POST /createProductPOST /products
DELETE /deleteProduct/10DELETE /products/10
GET /getUserOrders/5GET /users/5/orders

Każda metoda HTTP ma określoną semantykę, dlatego należy wykorzystywać ją zgodnie z przeznaczeniem.

Przykładowo, nie należy usuwać produktu za pomocą żądania GET:

GET /products/10/delete

Poprawnym rozwiązaniem jest:

DELETE /products/10

Podobnie podczas tworzenia zasobu należy zazwyczaj zwrócić kod 201 Created, a w przypadku próby pobrania nieistniejącego produktu — 404 Not Found.

2. Poprawnie wykorzystuj metody i kody HTTP

Każda metoda HTTP ma określoną semantykę, dlatego należy wykorzystywać ją zgodnie z przeznaczeniem.

Przykładowo, nie należy usuwać produktu za pomocą żądania GET:

GET /products/10/delete

Poprawnym rozwiązaniem jest:

DELETE /products/10

3. Stosuj filtrowanie, sortowanie i paginację

Endpoint zwracający kolekcję zasobów nie powinien bez ograniczeń pobierać wszystkich rekordów z bazy danych. W przypadku dużej liczby danych może to prowadzić do problemów z wydajnością oraz nadmiernego zużycia pamięci.

Dlatego warto stosować trzy mechanizmy:

Filtrowanie (Filtering) umożliwia pobieranie zasobów spełniających określone kryteria:

GET /products?category=electronics

Sortowanie (Sorting) pozwala określić kolejność zwracanych danych:

GET /products?sort=price,asc

Paginacja (Pagination) umożliwia pobieranie danych w mniejszych partiach:

GET /products?page=0&size=20

4. Wersjonuj REST API

Wraz z rozwojem aplikacji mogą pojawić się zmiany w strukturze zasobów, formacie odpowiedzi czy sposobie działania endpointów.

W przypadku zmian niekompatybilnych z dotychczasowym kontraktem API warto wprowadzić wersjonowanie, aby nie zakłócić działania istniejących klientów.

Jednym z najprostszych rozwiązań jest wersjonowanie w adresie URI:

GET /api/v1/products
GET /api/v2/products

struktury odpowiedzi.

5. Zadbaj o spójną obsługę błędów

REST API powinno zwracać nie tylko odpowiednie kody HTTP, ale również czytelne informacje umożliwiające klientowi zrozumienie przyczyny błędu.

Dobrym rozwiązaniem jest wykorzystanie standardu Problem Details for HTTP APIs (RFC 9457).

Przykładowa odpowiedź dotycząca błędu walidacji:

HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json

{
  "type": "https://api.example.com/problems/validation-error",
  "title": "Validation error",
  "status": 422,
  "detail": "Product data is invalid",
  "errors": [
    {
      "field": "price",
      "message": "Price must be greater than zero"
    }
  ]
}

Pole errors jest w tym przykładzie rozszerzeniem standardowego formatu Problem Details.

6. Zadbaj o bezpieczeństwo API

REST API często udostępnia dane użytkowników oraz operacje biznesowe, dlatego jego bezpieczeństwo powinno być uwzględnione już na etapie projektowania.

Najważniejsze praktyki obejmują:

  • HTTPS – szyfrowanie komunikacji pomiędzy klientem a serwerem.
  • Uwierzytelnianie (Authentication) – weryfikację tożsamości klienta, np. za pomocą tokenu OAuth 2.0.
  • Autoryzację (Authorization) – sprawdzanie, czy klient ma uprawnienia do wykonania operacji na konkretnym zasobie.
  • Walidację danych wejściowych – kontrolę poprawności danych przesyłanych do API.
  • Rate Limiting – ograniczanie liczby żądań wykonywanych przez klienta w określonym czasie.
  • Ochronę danych wrażliwych – unikanie przekazywania haseł, tokenów oraz innych sekretów w adresach URL.

7. Dokumentuj REST API

Dobrze zaprojektowane API powinno posiadać aktualną dokumentację opisującą dostępne endpointy, parametry żądań, formaty odpowiedzi oraz możliwe błędy.

Jednym z najpopularniejszych standardów jest OpenAPI Specification (OAS), umożliwiający opisanie kontraktu API w formacie JSON lub YAML.

Do prezentacji dokumentacji można wykorzystać Swagger UI, który umożliwia również interaktywne wykonywanie żądań.

Podsumowanie

REST API to jedno z najpopularniejszych rozwiązań wykorzystywanych do komunikacji pomiędzy aplikacjami, szczególnie w architekturze mikroserwisowej oraz systemach webowych. Dzięki wykorzystaniu standardowych mechanizmów protokołu HTTP umożliwia tworzenie prostych, elastycznych i łatwych w integracji interfejsów.

W artykule omówiłem podstawowe zasady architektury REST, metody HTTP, kody odpowiedzi oraz sposoby wymiany danych pomiędzy klientem a serwerem. Przedstawiłem również dobre praktyki projektowania API i prosty przykład implementacji CRUD w Java i Spring Boot.

Warto pamiętać, że dobrze zaprojektowane REST API to nie tylko zestaw endpointów zwracających JSON. Kluczowe znaczenie mają odpowiednie wykorzystanie metod i kodów HTTP, bezstanowość komunikacji, spójne nazewnictwo zasobów oraz prawidłowa obsługa błędów.

REST nie jest rozwiązaniem idealnym dla każdego przypadku użycia, jednak dzięki swojej prostocie, szerokiemu wsparciu technologicznemu i wykorzystaniu standardów HTTP pozostaje jednym z podstawowych podejść do projektowania API we współczesnych aplikacjach.

Dodaj komentarz