REST API

Jak tworzyć REST API?

W tym artykule przedstawię podstawowe zasady tworzenia REST API, czyli usług zorientowanych na zasoby (resources). Dowiesz się, jak tworzyć API w prawidłowy sposób. Co to są poziomy zaawansowania REST API, a także czy wersjonować API swoich usług.

 

Co to jest REST?

REST (Representational state transfer) to zestaw praktyk, które pomagają tworzyć współczesne web serwisy. Nie jest to żadna specyfikacja, więc programiści mają pewną dowolność w implementowaniu RESTa. Istnieje jednak całkiem sporo różnego rodzaju reguł, które pomagają wprowadzić dobre praktyki w jego implementacji.

Dwie charakterystyczne cechy usług restowych to: zorientowanie na zasoby i bezstanowość usług.

 

Poziomy zaawansowania REST API

Do sklasyfikowania różnego rodzaju API restowego możemy posłużyć się modelem dojrzałości Richardsona, który dzieli REST API na 4 różne poziomy.

Poziom 0

API implementujące ten poziom zwykle nie korzysta z wielu adresów URI (jeden URI na cały serwis), nie korzysta z wielu metod http (zwykle wykorzystuje tylko POST), nie korzysta także z HATEOAS (Hypermedia as the Engine of Application State). Mogą to być web serwisy podobne do np. SOAP lub XML-RPC (z tą różnicą, że w SOAP jest dodatkowo koperta, która opakowuje zawartość).

Poziom 1

W pierwszym poziomie usługi zorientowane są na zasób. Wykorzystywane są unikalne adresy URI do rozróżnienia poszczególnych zasobów. W użyciu są zwykle tylko metody GET i POST:

Poziom 2

W poziomie tym używane są dodatkowe metody http: GET, POST, PUT, PATCH, DELETE. Metody te powinny być używane zgodnie ze swoim przeznaczeniem. Poza tym API powinno korzystać z odpowiednich statusów http.

Poziom 3

Poziom 3 zakłada obsługę HATEOAS (Hypermedia as the Engine of Application State). Dzięki czemu w odpowiedzi wysyłane są dodatkowe linki pozwalające poruszać się po API. Dzięki temu klient API ma ułatwione zadanie i „wie”, gdzie może pobrać dodatkowe informacje. Użycie HATEOAS pozwala zminimalizować dokumentację API.

Im wyższy poziom został zaimplementowany, tym nasze API jest bardziej zgodne z architekturą REST.

Który poziom zaimplementować?

Zwykle, gdy mówimy o „prawdziwych” RESTach, to w grę wchodzą poziomy 2 i 3. A najczęściej implementowany jest poziom 2 z tego względu, że często można obejść się bez zastosowania HATEOASa. Niektórzy też twierdzą, że HATEOAS powoduje dodatkowy poziom komplikacji i nie daje aż tak wiele w zamian. No i bez niego implementowanie API jest trochę szybsze.

Więcej możesz przeczytać w artykule Martina Fowlera Richardson Maturity Model.

 

Jak poprawnie tworzyć REST API?

Zacznijmy od odpowiedniego nazewnictwa w URI. Używamy rzeczowników w liczbie mnogiej np: /orders, /users, /customers. Adres zasobu musi być przygotowany w odpowiedni sposób :

resource1/{resource-id}/resource2/{resource-id}/resource3/{resource-id} itd.

Jeśli chcesz pobrać wszystkie zamówienia klienta, to URI będzie wyglądało tak: /customers/1/orders (gdzie 1-to id klienta). Jeżeli chcesz pobrać konkretne zamówienie, to: /customers/1/orders/1.

Używaj odpowiednich metod http

Odpowiednie metody http w połączeniu z odpowiednim nazewnictwem w URI daje nam spójną całość w postaci dobrze zdefiniowanych endpointów restowych:

GET /customers – zwraca listę obiektów

GET /customers/1 – zwraca pojedynczy obiekt

POST /customers – tworzy nowy zasób

PUT /customers/1 – aktualizuje dany zasób

DELETE /customers/1 – usuwa zasób

Podobnie dla bardziej rozbudowanych zasobów

GET /customers/1/orders – zwraca listę obiektów

GET /customers/1/orders/1 – zwraca pojedynczy obiekt

POST /customers/1/orders – tworzy nowy zasób

PUT /customers/1/orders/1 – aktualizuje dany zasób

DELETE /customers/1/orders/1 – usuwa zasób

Jakie statusy http stosować?

Najczęściej używanym statusem jest chyba status 200 OK. Ale to nie znaczy, że trzeba go stosować wszędzie. W przypadku zapytań POST można stosować status 201 Created lub 202 Accepted, jeśli zapytanie jest asynchroniczne.

Trzeba pamiętać o tym, żeby nie zwracać zawsze tego samego statusu do różnych sytuacji. Np.  w Springu domyślny status błędu to 500 Internal Server Error. Nie ważne czy sterownik bazy danych rzuci jakiś wyjątek, czy zostanie zwrócony błąd walidacji, to Spring zawsze zwróci status 500. Jest to bardzo niepoprawne, ponieważ są to dwie różne klasy problemów. W pierwszym wypadku np. aplikacja nie może się połączyć z bazą danych i nie funkcjonuje poprawnie. W drugim wszystko działa tak jak trzeba, tylko użytkownik wprowadził złe dane do aplikacji.

W drugim przypadku lepiej jest zwracać status 400 BAD REQUEST.

Poniżej lista różnych typów statusów:

1×× informacyjne
2×× sukcesu
3×× przekierowania
4×× błędy klienta
5×× błędy serwera

Spis wszystkich statusów http znajdziesz tutaj

Odpowiednio przygotowane odpowiedzi błędów

Dobrze jest, żeby odpowiedź z błędem zawierała jakieś pole, które opisuje ten błąd np. message. Nie jest to jednak w żaden sposób narzucone. Najlepiej jest zwracać znaczące komunikaty błędów, ale nie zawsze jest to pożądane. Czasem z różnych względów będziesz musiał zwracać generyczny komunikat „Wystąpił błąd, skontaktuje się z administratorem aplikacji” lub coś podobnego.

Domyślna odpowiedź w Spring Framework wygląda tak jak poniżej i zwykle jest ona wystarczająca, żeby dowiedzieć się co się stało w danej sytuacji:

Jak dodawać dodatkowe parametry?

Czasem jest potrzeba skorzystania z dodatkowych parametrów w aplikacji. Np. w sytuacji, gdy potrzebujemy stronicowania wyników. Wtedy najlepiej dodać odpowiedni parametr jako część query stringa w taki oto sposób: ?page=1.

Podobnie możesz zrobić z parametrami opcjonalnymi np: ?sort=id_asc lub połączyć je razem ?page=1&sort=id_asc.

Dodawanie parametrów opcjonalnych w ścieżce (URI) jest mało wygodne i może prowadzić do nieporozumień dlatego wygodniej jest dodawać je jako część query stringa.

Jak wykonywać akcje korzystając z REST API?

To chyba jedno z częściej pojawiających się pytań dotyczących REST API. I jeśli chcemy być zgodni z zaleceniami RESTa, to właściwie nie powinniśmy myśleć o akcjach, tylko o stanie, który te akcje powodują lub zmieniają (ST w REST to state transfer).

Załóżmy, że nasza akcja to stworzenie jakiegoś backupu. Stan backupu po wykonaniu akcji to „utworzony”, więc możemy posłużyć się tu po prostu statusem i wysłać następujące żądanie.

Zawsze po wywołaniu takiego endpointa stworzymy nowy backup.

Można też skorzystać z innego sposobu, chyba trochę mniej zgodnego z czystym RESTem, czyli użycie w URI akcji jako parametru.

Czasem sztywne trzymanie się wytycznych RESTa wprowadza zamęt zamiast pomagać. I warto poszukać najprostszego rozwiązania.

Czy wersjonować REST API?

Kolejny ważny problem REST API to ciągle powracające pytanie, czy powinniśmy je wersjonować, albo kiedy zacząć je wersjonować. Z moich doświadczeń wynika, że lepiej tego nie robić. Jeśli tego nie potrzebujesz, a zwykle tak jest, to po prostu tego nie rób. A dlaczego? Ponieważ jest to dosyć skomplikowane w utrzymaniu i bez względu na to jaką metodę wersjonowania zastosujesz to i tak będzie to trudne.

Jeśli już musisz wersjonować API, to chyba najlepszym sposobem jest dodanie odpowiedniego nagłówka http z numerem wersji. Pamiętać trzeba przy tym, że endpoint bez podania wersji powinien udostępniać API w wersji pierwszej (bazowej) inaczej może prowadzić to do nieporozumień.

 

Podsumowanie

Coraz więcej aplikacji korzysta z REST API. Jest to bardzo wygodny sposób tworzenia API i każdy developer powinien cokolwiek o nim wiedzieć. Często też na rozmowach rekrutacyjnych można spotkać się z pytaniami dotyczącymi RESTa np. „Jakiej metody http powinniśmy użyć do stworzenia nowego zasobu, a jakiej do aktualizacji?”.

Cały artykuł powstał w oparciu o podręcznik tworzenia API od Google, który znajdziesz poniżej w źródłach.

 

 

Źródła:

https://cloud.google.com/apis/design

https://martinfowler.com/articles/richardsonMaturityModel.html

https://httpstatuses.com

 

Mini kurs testy jednostkowe

Mateusz Dąbrowski

Cześć jestem Mateusz, zajmuję się programowaniem już ponad 12 lat z czego ponad 8 programuję w Javie. Zapraszam Cię do lektury mojego bloga. Możesz przeczytać więcej o mnie >>TUTAJ<<

3 thoughts to “Jak tworzyć REST API?”

  1. Cześć.

    Myślę, że warto było by wspomnieć o mniej popularnych metodach HTTP, mianowicie HEAD i OPTIONS. Pojawiają się one również na rozmowach rekrutacyjnych.

    Pozdrawiam,
    Damian

    1. Dzięki Damian za komentarz. W tzw. międzyczasie postaram się dopisać coś o tych metodach 😉

  2. Dodałbym, może trochę nie w temacie, taką uwagę – niech zaimplementowany REST zwraca sensowny, łatwo identyfikowalny zasób. Niech to nie będą to wymieszane pola kilku obiektów, z którego dopiero Twój klient ma skleić jakiś sensowny twór.
    To taka uwaga na marginesie po moich ostatnich doświadczeniach z zewnętrznym, restowym api, którego konsumentem jest pisana przez mój zespół aplikacja. Najwyraźniej zwracanie częściowych danych osobowych pomieszanych z adresem i przeplecionych konfiguracją konta googla to nowa meta niektórych ‚programistów’.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *