Richardson Maturity Model, warstwa 3 – HATEOAS

Dzisiaj ostatnia warstwa modelu, która zdecydowanie często jest pomijana w implementacjach REST. Moim zdaniem, w przypadku publicznych API jest bardzo ważna, szczególnie w środowisku mikro-serwisów, gdzie nawigacja jest utrudniona ze względu na liczbę usług.

HATEOAS to skrót od Hypertext As The Engine Of Application State. Mechanizm dostarcza możliwość nawigacji przez zasoby bez wiedzy o konkretnych adresach URL.  Załóżmy, że mamy bazę klientów w systemie i możemy w niej:

  1. Wylistować listę klientów.
  2. Zwrócić dane konkretnego klienta.
  3. Aktualizować dane.
  4. Usuwać klienta z bazy.
  5. Zwracać poszczególne dane takie jak dane kontaktowe, adres itp.

Projektując serwis zgodnie z poprzednimi zasadami, otrzymalibyśmy następujące linki:

  1. GET /customers
  2. GET /customers/{id}
  3. PUT /customers i w ciele dane klienta
  4. DELETE /customers/{id}
  5. GET customers/{id}/email, customers/{id}/address itd.

Bez warstwy trzeciej, klient musi znać te linki. Innymi słowy, klient musi znać implementację wewnętrzną serwera i w przypadku jakiejkolwiek zmiany, wszyscy klienci muszą zaktualizować kod. Klient tak naprawdę powinien tylko wiedzieć co chce zrobić, a nie jak to ma zrobić.

W przypadku hateoas, konsument musi znać dane tylko korzenia. Załóżmy, że wykonujemy zapytanie HTTP GET /customers, aby wylistować wszystkie osoby w bazie. Jako odpowiedz przyjdzie coś w rodzaju:

HTTP/1.1 200 OK <Customers> <Customer FirstName="Piotr" Last="Zielinski" Id="1"> <link rel = "details" uri = "/customers/1"/> <link rel = "address" uri = "/customers/1/address"/> </Customer> <Customer FirstName="afaf" Last="sfsagsa" Id="2"> <link rel = "details" uri = "/customers/2"/> <link rel = "address" uri = "/customers/1/address"/> </Customer> </Customers>

Analogicznie, dodając nową osobę do bazy czyli HTTP POST /customers/, dostaniemy w odpowiedzi również mapę linków:

HTTP/1.1 201 Created <Customer FirstName="Piotr" Last="Zielinski" Id="1"> <link rel = "details" uri = "/customers/1"/> <link rel = "address" uri = "/customers/address"/> </Customer>

Jak widzimy, to serwer decyduje, co klient może zrobić. Odpowiedź określa również aktualny stan aplikacji, czyli co możemy ze zwróconymi zasobami, w danym momencie zrobić.  API zaprojektowane w ten sposób ma zatem wbudowany mechanizm discovery – przekazujemy konsumentowi tylko korzeń, a on sam już jest w stanie przeglądać i wykonywać dowolne operacje na zasobach.

3 thoughts on “Richardson Maturity Model, warstwa 3 – HATEOAS”

  1. Wszystko fajnie. Nie jestem jednak pewien czy prawdą jest że “Odpowiedź określa również aktualny stan aplikacji”. Wniosek podobny czyli “co możemy ze zwróconymi zasobami” ale nie nazwałbym tego “stanem aplikacji”. Po pierwsze mówimy o komunikacji bezstanowej a po drugie w tym samym czasie gdy np. dodamy jakiś zasób może on być usunięty przez kogoś innego i już nie uzyskamy dostępu np. do zwróconych w linkach zasobów po dodaniu.

Leave a Reply

Your email address will not be published.