Model dojrzałości REST API Leonarda Richardsona

Styczeń 12, 2024 | #rest-api

000000
001000
010001
100001

W tym artykule:

  1. REST vs RESTFul
  2. Zasady REST Roya Fieldinga
  3. Model dojrzałości REST API Leonarda Richardsona
  4. Zasoby są kluczowym elementem architektury REST
  5. Czasowniki HTTP a operacje REST API
  6. Odpowiedzi z RESTful API
  7. Samoopisujące się REST API

Więcej w temacie REST API

REST vs RESTFul

Terminy "REST" i "RESTful" odnoszą się do architektury oprogramowania i sposobu projektowania usług internetowych. O ile REST to zbiór wytycznych i zasad projektowych dla usług sieciowych, o tyle RESTful to określenie używane do opisania usług lub API, które przestrzegają tych zasad. Czyli, gdy mówimy, że API jest "RESTful", oznacza to, że zostało zaprojektowane zgodnie z zasadami REST.

Zasady REST Roya Fieldinga

Specyfikacje opisujące zasady REST (Representational State Transfer) nie są zawarte w jednym formalnym dokumencie, tak jak ma to miejsce w przypadku wielu innych standardów technologicznych. Zasady REST zostały pierwotnie sformułowane przez Roya Fieldinga w jego rozprawie doktorskiej z 2000 roku pt. "Architectural Styles and the Design of Network-based Software Architectures".

Oto kluczowe aspekty opisane przez Fieldinga, które definiują architekturę REST:

  1. Bezstanowość (Statelessness): Każde zapytanie od klienta do serwera musi zawierać wszystkie informacje potrzebne do zrozumienia i przetworzenia zapytania. Serwer nie przechowuje informacji o stanie klienta między zapytaniami.

  2. Buforowalność (Cacheable): Odpowiedzi muszą być jasno zdefiniowane jako możliwe do buforowania lub nie, co pozwala klientom na buforowanie odpowiedzi w celu poprawy wydajności.

  3. Klient-Serwer (Client-Server): Funkcje systemu są podzielone między serwery, które dostarczają zasoby lub usługi, i klientów, którzy korzystają z tych usług, co ułatwia skalowalność i portowalność.

  4. Jednolity interfejs (Uniform Interface): Uproszczenie i dekupling architektury, co pozwala na niezależny rozwój różnych części aplikacji. To obejmuje użycie standardowych metod HTTP i komunikację poprzez zasoby, które są zazwyczaj reprezentowane jako URL-e.

  5. System warstwowy (Layered System): Klient nie musi wiedzieć, czy komunikuje się bezpośrednio z serwerem końcowym, czy z pośrednikiem, co umożliwia skalowanie i zwiększa bezpieczeństwo.

  6. Kod na żądanie (Code on Demand): Serwery mogą (jest to warunek opcjonalny) tymczasowo rozszerzyć lub dostosować funkcjonalność klienta przez przesyłanie kodu wykonywalnego.

Ponieważ specyfikacja REST jest bardziej zbiorem wytycznych niż ścisłym standardem, implementacje RESTful mogą różnić się między sobą, ale wszystkie powinny przestrzegać powyższych ogólnych zasad.

Model dojrzałości Richardsona

W 2008 roku podczas prezentacji współprowadzonej z Martinem Fowlerem, znanym autorem i ekspertem w dziedzinie architektury oprogramowania Leonard Richardson zaprezentował opracowany przez siebie model klasyfikacji REST API na podstawie ich zgodności z zasadami architektury REST zdefiniowanymi przez Roya Fieldinga.

Richardson Maturity Model (RMM) składa się z czterech poziomów (0-3), gdzie każdy kolejny poziom reprezentuje wyższy stopień dojrzałości i zgodności z ideą REST.

  1. Poziom 0 - Bagno POX (The Swamp of POX): Na tym poziomie, API nie stosuje żadnych zasad REST. Zwykle jest to pojedynczy URI, który reaguje na różne komendy przekazywane w ciele żądania. POX oznacza "Plain Old XML" i odnosi się do interfejsów sieciowych opierających się na prostych XML-owych protokołach.

  2. Poziom 1 - Zasoby (Resources): Na tym poziomie, API jest zorganizowane wokół zasobów, ale nie wykorzystuje jednolitego interfejsu (metod HTTP) do manipulacji tymi zasobami.

  3. Poziom 2 - Czasowniki HTTP (HTTP Verbs): API na tym poziomie korzysta z odpowiednich metod HTTP (GET, POST, PUT, DELETE itd.) do operacji na zasobach, oraz z kodów stanu HTTP do reprezentowania wyników operacji. To zbliża API do pełnej zgodności z REST.

  4. Poziom 3 - Hipermedia jako silnik stanu aplikacji (HATEOAS): Tutaj hipermedia wchodzą w grę. Na tym poziomie, API w pełni stosuje zasadę HATEOAS. Odpowiedzi serwera zawierają hiperłącza, które informują klienta o możliwych kolejnych krokach, które może podjąć. To znaczy, że stan aplikacji jest napędzany przez hipermedia, a klienty API są w pełni naprowadzane przez odpowiedzi serwera.

Zasoby są kluczowym elementem architektury REST

Zasoby odnoszą się do różnych obiektów, danych lub usług, które są dostępne przez API dla klientów.

Każdy zasób REST API jest unikalnie identyfikowany za pomocą URI (Uniform Resource Identifier).

W RESTful API URI przyjmuje formę URL-a identyfikując zasób i dając do niego dostęp. Składa się on ze standardowych elementów takich jak protokół, host, port, ścieżka i parametry.

Ścieżka odnosi się do konkretnego zasobu lub grupy zasobów w API. Jest to hierarchiczna struktura, która może zawierać kilka segmentów.

Zasoby definiujemy używając rzeczowników w liczbie mnogiej. np /users, natomiast do konkretnego użytkownika odwołujemy się używając jego jednoznacznego identyfikatora np. /users/123 albo /articles/rest-api-best-practices

Jeśli jakiś zasób występuje tylko w liczbie pojedynczej dopuszczalne jest użycie rzeczownika w liczbie pojedynczej np. /me - odnoszące się do obiektu aktualnie zalogowanego użytkownika, albo /users/123/cart, ale są to raczej wyjątki.

Możemy zagnieżdżać zasoby np /users/123/orders/456 ale dobrze jest nie przekraczać dwóch poziomów zagnieżdżenia i mieć możliwie jak najbardziej płaską strukturę zasobów.

Zamiast brnąć w zagnieżdżenia /users/123/orders i /users/123/orders/456/items

Lepie użyć filtrowania

można zrobić /orders?user_id=123 i /order-items/order_id=456

Parametry zapytania (Query Parameters) mogą być dodane do URI, aby dostosować żądanie

Parametry zapytania są dodawane po ścieżce i rozpoczynają się od znaku zapytania ?, a poszczególne parametry są od siebie oddzielone znakiem &. Dzięki temu na jednym zasobie możemy wykonać równocześnie kilka operacji. Mogą to być:

  • filtrowanie np. /products/price__lt=100 - zwróci produkty tańsze niż 100 PLN. Musimy zadbać aby nasz backend rozumiał co oznaczają sufiksy __lt, __gte, __eq itd. To akurat przykład konwencji zaczerpnięty ze świata Django.

  • wyszukiwanie np. /books?q=Harry - będzie szukać książek zawierających słowo "Harry" np. w tytule, opisie, w nazwie autora. W tym przypadku parametr q "rezerwujemy" dla funkcjonalności wyszukiwania i określamy jakie pola dla danego zasobu mają być przeszukiwane podczas tej operacji.

  • sortowanie /authors?sort=-last_name,first_name - tym razem parametr sort jest dedykowany funkcjonalności sortowania. Podajemy w nim nazwy pól rozdzielonych przecinkiem po jakich ma nastąpić sortowanie. Kolejność pól ma znaczenie. Znak minus - przed nazwą pola oznacza, że sortowanie po tym polu ma się odbywać w odwrotnej kolejności (descending).

  • paginacja /products?page=7&per_page=50

  • ograniczanie lub rozszerzanie wyniku odpowiedzi o dodatkowe dane - /alubms/23?embeded=artist.name,title - w podanym przykładzie chcemy otrzymać dane albumu ograniczone do jego tytułu i poszerzone o nazwę powiązanego z nim artysty.

Powyższe operacje nie wyczerpują katalogu możliwości.

Czasowniki HTTP a operacje REST API

O ile zasoby opisywane są rzeczownikami o tyle metody HTTP - przynajmniej te podstawowe jak GETPOSTPUTPATCH, and DELETE są w formie czasowników.

Standardowe metody HTTP

Metody HTTP są podstawą dla interakcji klient-serwer w REST API i pozwalają na wyraźne i jednoznaczne określenie intencji żądania.

Każda z tych metod ma określone znaczenie i jest używana w specyficznych scenariuszach. Oto najczęściej używane metody HTTP w REST API:

  1. GET: Używana do pobierania danych z serwera. RFC 2616 - HTTP 1.1 section 9.1.1 opisuje metodę GET jako bezpieczną, co oznacza, że:

    • nie powoduje zmiany stanu zasobu
    • jest idempotentna - wielokrotne wywołanie tej samej metody GET daje ten sam wynik.
  2. POST: Używana do tworzenia nowego zasobu na serwerze. Nie jest idempotentna, co oznacza, że wielokrotne wysłanie tego samego żądania POST może skutkować utworzeniem wielu zasobów.

  3. PUT: Używana do aktualizowania istniejącego zasobu lub tworzenia nowego, jeśli nie istnieje. PUT jest idempotentna, więc wielokrotne wykonanie PUT z tymi samymi danymi na tym samym zasobie skutkuje tym samym stanem zasobu.

  4. DELETE: Używana do usunięcia zasobu z serwera. Tak jak PUT, DELETE jest również idempotentna, co oznacza, że wielokrotne wywołanie DELETE na tym samym zasobie daje ten sam wynik (zasób pozostaje usunięty).

  5. PATCH: Używana do częściowej modyfikacji istniejącego zasobu. PATCH jest mniej restrykcyjna niż PUT, ponieważ pozwala na aktualizację części zasobu, bez konieczności dostarczania pełnej reprezentacji.

Wyżej wymienione metody umożliwiają realizację czterech podstawowych operacji określonych akronimem CRUD.

  1. C - Create (Tworzenie): tworzenie nowych danych lub zasobów - POST.

  2. R - Read (Odczyt): odczytywanie lub pobierania istniejących danych - GET

  3. U - Update (Aktualizacja): aktualizacja istniejących danych lub zasobów - PUT lub PATCH

  4. D - Delete (Usuwanie): usuwanie danych lub zasobów - DELETE.

Dodatkowe metody HTTP

Mamy jeszcze inne metody HTTP takie Jak OPTIONS, HEAD, TRACE. Wiele popularnych frameworków do tworzenia REST API, takich jak Django Rest Framework (DRF) i FastAPI, automatycznie implementuje obsługę dla nagłówków OPTIONS i HEAD więc zwykle nie ma potrzeby modyfikacji ich obsługi. Zawsze jednak warto wiedzieć jak działają. Co do metody TRACE to jest ona zwykle pomijana z powodów, które opisuję niżej.

OPTIONS

Metod OPTIONS jest używana w REST API oraz w ogólnym kontekście protokołu HTTP do określenia opcji komunikacji z zasobem lub serwerem. Gdy klient wysyła żądanie OPTIONS, serwer odpowiada, wskazując, które metody HTTP są dozwolone dla danego zasobu. Odpowiedź może również zawierać inne informacje, takie jak nagłówki, które mogą być używane w żądaniach.

W przypadku żądań międzydomenowych, metoda OPTIONS jest często wykorzystywana jako "pre-flight request", gdzie przeglądarka automatycznie wysyła żądanie OPTIONS przed właściwym żądaniem (np. POST, PUT), aby sprawdzić, czy serwer zezwala na takie żądanie z poziomu innej domeny.

# żądanie
OPTIONS /api/resource

# Odpowiedź
HTTP/1.1 204 No Content
Allow: GET, POST, HEAD, OPTIONS

Metoda HTTP HEAD jest podobna do metody GET, ale z tą istotną różnicą, że serwer w odpowiedzi na żądanie HEAD zwraca tylko nagłówki HTTP, bez ciała odpowiedzi. Metoda HEAD pozwala klientowi sprawdzić dostępność zasobu i/lub metadane z nim związane, takie jak typ zawartości (Content-Type), długość zawartości (Content-Length), ostatnia modyfikacja (Last-Modified) i inne nagłówki, bez konieczności pobierania całości.

# żądanie
HEAD /api/resource

# odpowiedź
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 12345
Last-Modified: Wed, 21 Oct 2020 07:28:00 GMT

TRACE

Metoda HTTP TRACE jest stosunkowo rzadko używaną metodą, która służy do diagnostyki i debugowania w sieciach komputerowych. Głównym zadaniem TRACE jest odbicie żądania tak, aby klient mógł zobaczyć, co zostało otrzymane przez serwer, co może być przydatne w identyfikacji zmian lub dodatków dokonanych przez pośredników w ścieżce żądania.

Metoda TRACE jest często wyłączana na serwerach ze względów bezpieczeństwa. Jednym z zagrożeń związanym z TRACE jest potencjalne wykorzystanie w atakach typu Cross-Site Scripting (XSS), gdy serwer odbija treść żądania, która może zawierać szkodliwy skrypt.

# żądanie
TRACE /api/example
Header1: Value1
Header2: Value2

# odpowiedź
HTTP/1.1 200 OK
Content-Type: message/http

TRACE /api/example HTTP/1.1
Host: example.com
Header1: Value1
Header2: Value2

Punkt końcowy

Metoda HTTP + URI tworzy punkt końcowy (endpoint). Innymi słowy zasób i operacja, którą chcemy na tym zasobie wykonać tworzą dopiero konkretny punkt końcowy.

Odpowiedzi z RESTful API

Odpowiedzi z RESTful API powinny być jasno zdefiniowane, zrozumiałe i spójne, aby ułatwić korzystanie z API.

Kody statusu HTTP

Odpowiedzi powinny zawierać odpowiednie kody statusu HTTP, aby wskazać, czy żądanie zostało przetworzone pomyślnie czy nie. Tradycyjnie pewnym operacjom towarzyszą standardowe kody statusów.

Status 200 OK oznacza że udało się pobrać lub odczytać obiekt lub listę obiektów metodą GET. W przypadku nie odnalezienia zasobu zwykle zwracane jest 404 Not Found, ale jeśli ma to znaczenie możemy też zwrócić 410 Gone dając do zrozumienia, że ten zasób istniał, ale został trwale usunięty (np. przeniesiony do archiwum o czym informujemy w treści komunikatu.)

Status 201 Created zwykle towarzyszy metodzie POST informując o powodzeniu utworzenia nowego obiektu. Jeśli zostaną przesłane niepoprawne dane, co do typu, formatu itp. zwracany jest błąd 400 Bad Request. W przypadku przesłania poprawnych danych ale naruszających np. warunek integralności (unikalności) mamy możliwość zwrócenia bardziej precyzyjnego statusu 409 Conflict z reguły jednak najczęściej obsługiwane jest to zwykłą 400.

Powodzenie aktualizacji metodą PUT lub PATCH też zwykle kończy się kodem 200 OK, ale może równie dobrze kończyć się kodem 204 No Content, tak jak ma to miejsce w przypadku operacji usuwania - DELETE. To jaki kod należy zwrócić, zależy od tego czy po wykonaniu operacji zwracamy zaktualizowany obiekt lub link do niego, czy też nie zwracamy żadnych danych.

Dobrą praktyką jest zwracanie nowo utworzonej instancji w odpowiedzi metody POST, tak jak i zaktualizowanych danych odpowiednio dla metod PUT czy PATCH. Zwiększa to co prawda wielkość odpowiedzi ale najczęściej zapobiega konieczności pobrania nowego, czy zaktualizowanego zasobu osobnym żądaniem.

Format danych

Format danych dotyczy zarówno żądania, ale przede wszystkim odpowiedzi. Choć obecnie niepodzielnie "rządzi" JSON, jest o wiele więcej formatów, które są używane.

Oto najpopularniejsze formaty danych używane w REST API:

  1. JSON (JavaScript Object Notation): Jest to najczęściej używany format w REST API ze względu na jego lekkość, czytelność i łatwość obsługi w większości języków programowania. JSON jest idealny dla większości zastosowań internetowych.

  2. XML (eXtensible Markup Language): XML jest nadal używany, szczególnie w starszych systemach i w branżach, które przyjęły go jako standard (np. w finansach i telekomunikacji). XML jest dobrze znany ze swojej rygorystycznej struktury i zdolności do reprezentowania złożonych struktur danych.

  3. HTML (Hypertext Markup Language): Chociaż rzadko używany jako główny format odpowiedzi w typowych REST API, HTML może być przydatny, gdy API jest przeznaczone do bezpośredniego wyświetlania danych w przeglądarkach internetowych.

  4. YAML (YAML Ain't Markup Language): YAML jest czasem używany w API ze względu na swoją czytelność i prostotę, zwłaszcza w konfiguracjach lub w API skierowanych do deweloperów.

  5. PlainText: Prosty tekst może być używany dla bardzo prostych odpowiedzi, na przykład dla API zwracających tylko jedną wartość lub krótki komunikat.

  6. CSV (Comma-Separated Values): Format CSV jest przydatny w przypadku API, które dostarczają danych w formie tabelarycznej, co jest użyteczne np. dla aplikacji do analizy danych czy arkuszy kalkulacyjnych.

  7. Binary data: Dla API zwracających pliki lub dane binarne (np. obrazy, dokumenty PDF, pliki audio), odpowiedzi mogą być w formacie binarnym.

Wybór formatu danych zależy od specyfiki API i potrzeb jego użytkowników. Wiele API oferuje możliwość wyboru formatu danych przez klienta, na przykład poprzez użycie nagłówków HTTP (np. Accept: application/json) lub parametru w adresie URL /article?format=html To pozwala na większą elastyczność i może służyć różnym klientom API.

Ciekawą opcją jest też implementacja różnych kształtów odpowiedzi w ramach tego samego formatu np.

  • /categories?format=json - domyślnie zwraca wynik w postaci listy obiektów
  • /categories?format=json-tree - alternatywnie zwraca wynik w formie drzewa
{
  "categories": [
    {
      "id": 1,
      "name": "Electronics",
      "subcategories": [
        {
          "id": 101,
          "name": "Computers"
        },
        {
          "id": 102,
          "name": "Mobile Phones"
        }
      ]
    },
    {
      "id": 2,
      "name": "Home & Garden",
      "subcategories": [
        {
          "id": 201,
          "name": "Furniture"
        },
        {
          "id": 202,
          "name": "Gardening"
        }
      ]
    },
    {
      "id": 3,
      "name": "Automotive",
      "subcategories": []
    }
  ]
}

Taka zagnieżdżona struktura drzewiasta jest przydatna, na przykład, w sklepach internetowych lub innych systemach, które wymagają organizacji danych w hierarchicznej formie. Klienci API mogą używać tych danych do wyświetlania struktury kategorii w interfejsie użytkownika lub do innych celów nawigacyjnych.

Samoopisujące się REST API

HATEOAS (Hypermedia as the Engine of Application State) to element architektury aplikacji REST, które odróżnia ją od innych architektur aplikacji sieciowych.

Zasada HATEOAS podkreśla, że klient aplikacji powinien wchodzić w interakcję z aplikacją wyłącznie przez hipermedia, dostarczane dynamicznie przez serwer. Oznacza to, że klient API odkrywa dostępne akcje i zasoby za pośrednictwem hiperłączy zawartych w odpowiedziach od serwera, a nie przez wcześniejsze zakodowanie URI czy akcji. HATEOAS jest sposobem wykorzystania hipermediów do zarządzania stanem aplikacji. Podejście to ma na celu stworzenie bardziej odkrywalnego i samoopisującego się API.

Po wejściu na główny adres API githuba widzimy listę dostępnych zasobów, po których możemy poruszać się jak po stronie internetowej.

# Żądanie klienta
GET https://api.github.com

# Odpowiedź serwera
{
  "current_user_url": "https://api.github.com/user",
  "current_user_authorizations_html_url": "https://github.com/settings/connections/applications{/client_id}",
  "authorizations_url": "https://api.github.com/authorizations",
...
}

Podążając za zamieszonymi linkami uzyskujemy dostęp do kolejnych zasobów albo otrzymujemy dodatkowe informacje np link do dokumentacji.

# Żądanie klienta
GET https://api.github.com/user

# Odpowiedź serwera
{
  "message": "Requires authentication",
  "documentation_url": "https://docs.github.com/rest/users/users#get-the-authenticated-user"
}

Łącza hipermedialne mogą być realizowane w różnych formatach. Najbardziej popularne to JSON REST API i HAL, ale mogą Cię również zainteresować Siren, czy JSON-LD

Łącza hipermedialne w formacie JSON REST API

Referencje JSON REST API są opisane w specyfikacji RFC 5988 wedle której łącze powinno składać się z

  • Docelowy identyfikator IRI : każde łącze powinno zawierać docelowy międzynarodowy identyfikator zasobów (IRI). Jest to reprezentowane przez hrefatrybut.

  • Typ relacji łącza : typ relacji łącza opisuje, w jaki sposób bieżący kontekst (źródło) jest powiązany z zasobem docelowym. Jest to reprezentowane przez relatrybut.

  • Atrybuty docelowego IRI : Atrybuty łącza obejmują hreflangmediatitletypeoraz wszelkie parametry łącza rozszerzenia.

W praktyce może to wyglądać następująco

[{
  "id": 42,
  "title": "Harry Potter i kamień filozoficzny",
  "author": "J.K. Rowling",
  "isbn": "978-83-800-8211-3",
  "links": [
    {
      "rel": "self",
      "href": "https://example.com/books/42"
    },
    {
      "rel": "author",
      "href": "https://example.com/authors/123"
    },
    {
      "rel": "reviews",
      "href": "https://example.com/books/42/reviews",
    }
  ]
}]

Wartym uwagi w powyższym przykładzie jest odsyłacz do recenzji /reviews, które możemy odczytać metodą GET uzyskując listę recenzji, ale też dodać nową recenzję używając metody POST. Informację o dozwolonych metodach HTTP dla zasobu uzyskamy dzięki nagłówkowi Allow w odpowiedzi HTTP na żądanie wykonane metodą OPTIONS.

HTTP/1.1 200 OK
Allow: GET, POST
Content-Length: 0

Informacje w nagłówkach też są elementem samoopisującego się API i jak najbardziej wpisują się w ideę HATEOAS.

Hipermedia API w języku HAL

Hypertext Application Language (HAL) to konwencja definiowania relacji pomiędzy zasobami API REST w formacie JSON lub XML. Pomimo tego, że standard ten został pierwotnie zaproponowany w 2012 roku nie doczekał się jeszcze wersji końcowej i wciąż ma status projektu.

Hipermedia opisane tym językiem powinny zawierać

  • Docelowy URI : Wskazuje docelowy URI zasobu. Jest to reprezentowane przez hrefatrybut.

  • Relacja łącza : typ relacji łącza opisuje, w jaki sposób bieżący kontekst jest powiązany z zasobem docelowym. Jest to reprezentowane przez relatrybut.

  • Typ : wskazuje oczekiwany typ nośnika zasobu. Jest to reprezentowane przez typeatrybut.

{
  "_links": {
    "self": { "href": "https://example.com/books/42" },
    "author": { "href": "https://example.com/authors/123" }
  },
  "_embedded": {
    "author": {
      "_links": {
        "self": { "href": "https://example.com/authors/123" }
      },
      "id": 123,
      "name": "J.K. Rowling"
    }
  },
  "id": 42,
  "title": "Harry Potter i kamień filozoficzny",
  "author": "J.K. Rowling",
  "isbn": "978-83-800-8211-3",
}

W tym przykładzie, _links zawiera hiperłącza do zasobu książki i jej autora, a _embedded zawiera zagnieżdżony zasób autora z własnymi hiperłączami. Użycie HAL w JSON REST API ułatwia implementację HATEOAS, dostarczając standardowy sposób na reprezentację hiperłączy i zagnieżdżonych zasobów.

Zalety i wady HATEOAS

Odkrywalność

Klienci nie muszą wiedzieć z góry, jak zbudowane są URL-e do kolejnych stron, ponieważ otrzymują je bezpośrednio w odpowiedziach.

Przykłady

  • Odpowiedź na żądanie o listę artykułów /articles?category_id=3 dostarcza automatycznie hiperłącza do kategorii, po której nastąpiło filtrowanie /categories/3, szczegółów każdego z artykułów, linków do kolejnej i/lub poprzedniej strony paginacji

  • Odpowiedź na żądanie o szczegóły artykułu /artilcles/9 dostarcza hiperłączy do zasobów powiązanych np. informacji o autorach /artilcels/9/authors, zdjęć /articles/9/photos, komentarzy dotyczących artykułu /articles/9/comments itd.

Dostarczanie gotowego odnośnika pozwala po stronie klienta API na opracowanie generycznych rozwiązań opartych o wartość atrybutu rel opisującego rodzaj relacji a także atrybutów towarzyszących jak type, media, title itp.

W praktyce wiąże się to z dodatkową warstwą złożoności po stronie klienta co może zwiększyć czas i koszt rozwoju. Wymagania dotyczące designu czy wygody użytkowania UX (user experience) często utrudniają lub wręcz uniemożliwiają implementację zunifikowanych flow zmuszając deweloperów do "hardcodowania" pewnych fragmentów kodu aplikacji i z tych powodów użyteczność mechanizmów HATEOAS w tym zakresie może być ograniczona.

Elastyczność

Serwer może zmieniać strukturę URL-i bez wpływu na klientów, ponieważ linki są dynamicznie generowane i dostarczane w odpowiedziach. Backend może decydować, które akcje są dostępne, dzięki czemu interfejs użytkownika nie musi znać logiki biznesowej. 

Przykłady

  • Hiperłącza do zasobów powiązanych są generowane tylko jak użytkownik jest zalogowany i ma do nich dostęp np. link do kodów promocyjnych użytkownika /users/4/promocodes. Frontend nie musi odpytywać o uprawnienia ani znać zasad przyznawania kodów promocyjnych na podstawie aktywności użytkownika.
  • Jeśli do artykułu został dołączony film pojawia się hiperłącze odsyłające do tego zasobu /articles/8/movies

Jako programista klienta musisz być przygotowany na obsługę zasobów, które mogą się "pojawić" dlatego zamiast znikających odsyłaczy być może wolisz po prostu odpytać punkt końcowy, a o dostępności zasobu wywnioskujesz z kod statusu np. 404 Not Found, albo 403 Forbidden. Z drugiej strony o tym, że coś jest niedostępne dowiesz się dopiero kiedy zażądasz odpowiedzi, podczas gdy brak odsyłacza da Ci tę informację natychmiast. Możesz ją łatwo skorelować z mechanizmem ukrywania/deaktywacji tych części interfejsu, które są związane z nieosiągalnym zasobem.

Samoopisowość

Odpowiedzi zawierające linki HATEOAS są bardziej samoopisowe. Ułatwia to zrozumienie i wykorzystanie API przez nowych użytkowników i deweloperów, ale wciąż nie zastąpi to poprawnie przygotowanej dokumentacji wzbogaconej o sandbox. Ponadto należy wspomnieć, o rozmiarach odpowiedzi, które puchną pod wpływem dodatkowych danych. Choć hipermedia niewątpliwie ubogacają ładunek informacyjny niesiony w odpowiedzi niekiedy priorytet stawia się na wydajność i przepustowość. Samoopisowość API ma znaczenie na etapie dewelopmentu, natomiast w chwili działania może stanowić już tylko zbędne obciążenie dlatego dobrą praktyką jest taka implementacja metadanych w odpowiedzi z API REST aby dało się je deaktywować w środowisku produkcyjnym gdzie każdy zbędny bajt przesłany do klienta robi różnicę, albo jak w przypadku publicznych API dać klientowi możliwość decydowania za pomocą parametrów lub nagłówka czy chce odpowiedziach z API z HATEOAS.

Accept: application/hal+json

Akceptuję Ta strona zapisuje niewielkie pliki tekstowe, nazywane ciasteczkami (ang. cookies) na Twoim urządzeniu w celu lepszego dostosowania treści oraz dla celów statystycznych. Możesz wyłączyć możliwość ich zapisu, zmieniając ustawienia Twojej przeglądarki. Korzystanie z tej strony bez zmiany ustawień oznacza zgodę na przechowywanie cookies w Twoim urządzeniu.