w , , ,

FajneFajne Dobre!Dobre! ŚwietnieŚwietnie Że co?Że co? WnerwWnerw SmuteczekSmuteczek

REST API – Efektywna Droga Do Zrozumienia

REST API to jeden z najpopularniejszych stylów architektonicznych, którego znajomość jest niezbędna na rynku pracy backend developerów. W tym artykule pomogę Ci zbudować grunt teoretyczny.

Jeśli nie możesz doczekać się implementacji i praktyki, to zachęcam Cię do przeczytania mojego artkułu Architektura REST API w ramach którego opisuje jak zacząć implementację z wykorzystaniem Spring Boot.

Natomiast jeśli chcesz mieć teorię i praktykę w ramach jednego wideo, to przewiń artykuł na dół – tam znajdziesz zapis z mojego otwartego szkolenia online na temat tworzenia REST API 🙂

Czym jest i jak działa REST API?

Obrazując działanie API można porównać je do pracy kelnera. Jego zadaniem jest dostarczenie tego co zażąda (Request) klient. Jedzenie z kuchni to natomiast dane, które wracają w postaci odpowiedzi (Response).

Obrazowy przykład serwowania danych przez REST API
API serwuje określone dane podobnie jak restauracja serwuje określone dania.

REST API serwuje dane najczęściej w postaci JSON’a lub XML’a (o czym opowiem Ci później). Najczęściej zasoby pobierane z REST API są wykorzystywane na potrzeby innych aplikacji.

Komunikacja odbywa się poprzez dostęp do zasobu (można porównać go do miejsca w którym stoi restauracja), który jest zdefiniowany w punkcie końcowym. Punkt końcowy jest również bardzo często nazywany endpointem.

Najczęściej adres usługi ma następującą strukturę:

http://<adres-ip-servera>:<port-aplikacji>/<endpoint>

np.:

http://localhost:8080/cars

REST API i protokół HTTP

Jak widzisz dostęp do zasobu odbywa się z wykorzystaniem protokołu HTTP. Należy pamiętać, że REST stanowi jedynie styl architektoniczny i teoretycznie jest on niezależny od protokołu. Jednak jest w praktyce jest on łączony z protokołem HTTP. Więcej na temat tego protokołu i jego wersjach przeczytasz w moim artykule HTTP/3 – wszystko co programista musi o nim wiedzieć.

Podsumowując wraz z wykorzystaniem REST’a wiąże się wykorzystanie tzw. czasowników HTTP. Jest ich kilkanaście, jednak 5 podstawowych, które trzeba znać to:

GET

  • Pobiera określony zasobu według podanego identyfikatora.

POST

  • Tworzy nowy zasób.
  • Jest wykorzystywany do wszystkich innych operacji, które nie wpisują się w ramy innych metod.
  • Może służyć do pobierania danych w przypadku kiedy musimy w ramach body dostarczyć dodatkowe parametry.

PUT

  • Aktualizuje dany zasób na podstawie podanego identyfikatora.
  • Może służyć do tworzenia nowego zasobu jeśli jego identyfikator jest znany.

DELETE

  • Usuwa określony zasób według identyfikatora.

PATCH

  • Aktualizuje część wskazanego zasobu.
  • Od PUT’a różni się tym, że aktualizuje jedynie część zasobu.

Odpowiedź pochodząca z REST API

Formaty danych jakie możemy otrzymywać z REST API to najczęściej:

  • JSON – JavaScript Object Notation
  • XML – Extensible Markup Language

Z czego najpopularniejszy jest JSON ze względu na lekkość. Dla przykładu JSON:

{
   "name":"Przemek",
   "age":18,
   "website":"bykowski.pl"
}

oraz XML, który dostarcza te same dane:

<person>
   <name>Przemek</name>
   <age>30</age>
   <website>bykowski.pl</website>
</person>

Jak widać, odpowiedz w formacie XML ma znacznie większą ilość znaków co przekłada się na większy ruch sieciowy i dłuższy czas transferu danych. Dlatego najpopularniejszym formatem jest lekki JSON. Mile widzianym zwyczajem jest również dostarczanie konsumentowi Twojego API wyboru – jaki format danych ma otrzymać.

Model dojrzałości REST API

Model dojrzałości nazywany również modelem dojrzałości Richardsona opisuje poziomy implementacji REST’a.

LEVEL 0: THE SWAMP OF POX

Udostępniania usługi na wskazanym, jednym adresie, bez podziału na metody HTTP. Klient przekazuje w żądaniu informacje na temat działania jakie chce wykonać.

LEVEL 1: RESOURCES

Dostęp do zasobów odbywa się po konkretnych adresach bez podziału na metody HTTP:

http://localhost:8080/cars/get
http://localhost:8080/cars/add
http://localhost:8080/cars/update
http://localhost:8080/cars/delete

LEVEL 2: HTTP VERBS

Stały adres i czasowniki HTTP

GET http://localhost:8080/cars/
POST http://localhost:8080/cars/
PUT http://localhost:8080/cars/
DELETE http://localhost:8080/cars/

LEVEL 3: HIPEREMIA CONTROLS

Polega to na uwzględnieniu dodatkowej dokumentacji na temat naszego API. Jest to dłuższe zagadnienie, więc na ten temat nagrałem osobne wideo:

Model dojrzałości Richardsona – podsumowanie

Najczęściej większość implementacji REST’a zatrzymuje się na poziomie 2. Jest on wystarczający dla większości przypadków. Poziom trzeci często budzi kontrowersje pomiędzy kosztami implementacji/utrzymania, a potrzebom wykorzystania.

Statusy odpowiedzi

Protokół HTTP dostarcza wiele statusów odpowiedzi, którymi możemy dostarczać klientowi w zależności od przebiegu jego żądania. Jest 5 podstawowych grup:

  • 1xx – informacyjne
  • 2xx – powodzenie realizacji
  • 3xx – przekierowania
  • 4xx – błąd po stronie klienta
  • 5xx – błąd po stronie serwera

Poniżej dostarczam Ci ściągę, która dostarcza informacje jaki kod powinniśmy zwrócić w zależności od podjętego działania.

Implementacja REST API
Implementacja REST API – kliknij, aby powiększyć

6 warunków REST API

Mając już cały przekrój informacji to na podsumowanie dodaje 6 (5) warunków bez których REST nie istnieje. Warto je znać, raczej nie uczyć się na pamięć.
Kiedy nabierzesz praktyki, to wszystkie warunki stają się oczywiste i łatwe do odtworzenia 😉.

  1. Architektura klient-serwer – klient musi skomunikować się z serwerem aby
    uzyskać dostęp do usługi.
  2. Jednolity interfejs – dla realizacji konkretnego działania jest tylko jedna droga dojścia.
  3. Bezstanowość – bez względu na to jakie wcześniej operacje zostały wykonane, to zawsze każda kolejna operacja nie będzie zmieniała rezultatu dla innej.
  4. Możliwość zapisywania danych w buforze – wszystkie żądania, które trafiają do REST’a powinny być zapisane w buforze, jeżeli serwer nie jest w stanie obsłużyć na bieżąco wszystkich żądań.
  5. System warstwowy – jasny podział na warstwy. Użytkownik niekoniecznie musi mieć dostęp bezpośrednio do aplikacji – aplikacja może mieć dodatkową warstwę np. uwierzytelniającą.
  6. Kod na żądanie – opcjonalny warunek (ale mile widziany). Użytkownik po wykonaniu danego żądania, może otrzymać odpowiedź zwrotną w formie kodu, który następnie może wykorzystać w swojej aplikacji.

Pytanie z rozmowy rekrutacyjnej na temat REST API

Ważną cechą REST’a o której trzeba pamiętać to idempotentność. Ma ona ścisły związek z punktem trzecim opisanym w powyższym akapicie. W najprostszym ujęciu idempotentność jest to ponowienie wykonywania operacji, która nie zmienia rezultatu. Działanie to jest znane głównie z algebry, gdzie przykładem jest wartość bezwzględna:

|x| = x
|-5| = 5
|||-5||| = 5 // wielokrotne
wyciąganie wartości bezwzględnej nie wpłynie na zmianę rezultatu.

W kontekście REST API idempotentność oznacza, że dowolna liczba powtarzających się, identycznych żądań pozostawi zasób w tym samym stanie.

Przykład

Wysyłając żądanie o usunięcie zasobu o ID 1, sprawi że ten zasób zostanie usunięty.

curl -X "DELETE" http://localhost:8080/cars/1

Jednak powtarzając dokładnie to samo żądanie, to nic nie zmienimy. Żaden inny zasób nie ucierpi w przypadku, kiedy ponowimy wykonanie żądania. Wyjątkiem jest metoda POST (a w szczególnych przypadkach również PATCH). Ponieważ POST zawsze tworzy nowy zasób.

Warto o tym pamiętać, ponieważ to pytanie również często pojawia się na rozmowie o pracę

Czasami musimy ponowić wykonywanie operacji. Warto pamiętać, które metody, można bezpiecznie ponowić. Nie pomyl się jak tutaj 😉 Takie rzeczy wyjaśniamy sobie w ramach AkademiaSpring.pl

Czy PATCH jest idempotentny?

Wszystko zależy od jego implementacji. W większości przypadków jest idempotentny, jednak są przypadki kiedy jego stosowanie może być nieidempotentne i to najlepiej będzie mi to pokazać Ci na uproszczonym przykładzie:

Idempotentny przykład:

// orginal resource
{
   "name":"Przemek",
   "age":18,
}
// PATCH request
{
   "name":"Przemek",
   "age":20,
}
// resource after request
{
   "name":"Przemek",
   "age":20,
}

nieidempotentny przykład:

// orginal resource
{
   "name":"Przemek",
   "age":18,
}
// PATCH request
{
   "name":"Przemek",
   $increment: 'age'
}
// resource after request
{
   "name":"Przemek",
   "age":20,
}

Wartość age może być auto inkrementującą się, integralną częścią zasobu. Metoda PUT nadpisałaby tę wartość (ponieważ nadpisuje wszystko), jednak niekoniecznie zadziała to tak w przypadku metody PATCH.

Implementacja REST API w praktyce

Zobacz jak tworze REST API z wykorzystaniem Spring Boot w trakcie jednego z moich otwartych szkoleń online.

Źródła

https://www.restapitutorial.com
https://martinfowler.com/articles/richardsonMaturityModel.html
https://softwareengineering.stackexchange.com

I oczywiście ten temat szerzej poszerzam w swojej książce Spring Boot: LiveBook, dlatego zachęcam Cię do zapoznania się z nią 😉

Dołącz do mojego newstlettera dla początkujących!

Jeśli chcesz otrzymywać ode mnie regularne wiadomości dotyczące implementacji podobnych rozwiązań z wykorzystaniem Spring Boot, to zapisz się:

a ten newsletter już dla doświadczonych Springowców 😊 👇

Napisane przez Przemysław Bykowski

Aktywny programista i energiczny trener. Specjalizuje się w Spring Boot i uczę go w ramach AkademiaSpring.pl. Po godzinach udzielam się na YouTubach. Więcej o mnie.

Dodaj komentarz

Schemat działania Spring Context

Spring Context – Jak Działa Kontener IoC?

Pisanie książek IT

Pisanie Książki w IT – Szczerze o Tym, czy warto