Po co HATEOAS po stronie klienta?

35

Jak obecnie rozumiem, HATEOAS polega w zasadzie na wysyłaniu razem z każdą odpowiedzią linków z informacjami o tym, co robić dalej. Jeden prosty przykład można łatwo znaleźć w Internecie: system bankowy wraz z zasobem konta. Przykład pokazuje tę odpowiedź po żądaniu GET do zasobu konta

GET /account/12345 HTTP/1.1 HTTP/1.1 200 OK 
<?xml version="1.0"?> 
<account> 
    <account_number>12345</account_number> 
    <balance currency="usd">100.00</balance> 
    <link rel="deposit" href="/account/12345/deposit" /> 
    <link rel="withdraw" href="/account/12345/withdraw" /> 
    <link rel="transfer" href="/account/12345/transfer" /> 
    <link rel="close" href="/account/12345/close" /> 
</account>

Wraz z danymi znajdują się linki informujące, co można zrobić dalej. Jeśli saldo jest ujemne, mamy

GET /account/12345 HTTP/1.1 HTTP/1.1 200 OK 
<?xml version="1.0"?> 
<account> 
    <account_number>12345</account_number> 
    <balance currency="usd">-25.00</balance> 
    <link rel="deposit" href="/account/12345/deposit" /> 
</account>

Abyśmy mogli tylko dokonać wpłaty. Wszystko w porządku, jeśli korzystamy z Fiddlera lub wysyłamy zapytania za pomocą przeglądarki, możemy łatwo zobaczyć, co można zrobić. Tego rodzaju informacje są przydatne, abyśmy mogli odkryć możliwości API, a serwer jest oddzielony od klienta.

Chodzi jednak o to, że kiedy budujemy klienta, takiego jak SPA z Javascriptem, aplikacja na Androida lub wiele innych rzeczy, nie widzę, jak HATEOAS jest nadal aktualny. Chodzi mi o to: kiedy koduję SPA w javascript, muszę wiedzieć, co można zrobić w interfejsie API, aby napisać kod.

Muszę więc znać zasoby, obsługiwane metody, czego oczekują i co oddają, aby napisać wywołania ajax na serwerze, a nawet aby zbudować interfejs użytkownika. Kiedy tworzę interfejs użytkownika, muszę wiedzieć, że po złożeniu wniosku o konto można na przykład dokonać wpłaty na konto, w przeciwnym razie nie będę mógł podać tej opcji w interfejsie użytkownika. Potrzebuję też znać identyfikator URI, aby dokonać wpłaty w celu zbudowania wywołania ajax.

Mam na myśli to, że kiedy wysyłamy żądania do interfejsu API, łącza pozwalają nam lepiej odkrywać interfejs API i korzystać z niego, ale kiedy budujemy klienta, tworzona przez nas aplikacja nie będzie po prostu patrzeć na łącza, a następnie sama renderować poprawny interfejs użytkownika i wykonaj prawidłowe wywołania ajax.

Jak więc HATEOAS jest ważny dla klientów? Dlaczego w ogóle zawracamy sobie głowę HATEOAS?

użytkownik1620696
źródło
1
Masz rację, ale nie o to chodzi. HATEOAS powstrzymuje Cię przed budowaniem identyfikatorów URI dla łączy na stronie na kliencie.
James McLeod

Odpowiedzi:

24

tworzona przez nas aplikacja nie będzie po prostu patrzeć na linki, a następnie sama renderować poprawny interfejs użytkownika i wykonywać prawidłowe wywołania ajax

W rzeczywistości, to jest dokładnie to, co hateoas będzie dać UI. Nie to, co jest możliwe, ale kiedy jest to możliwe. Formalne HATEOAS, takie jak HAL , jak stwierdza pytanie, zawiera linki wskazujące, co jest możliwe. Ale kiedy pojawią się te linki, zależy od stanu aplikacji. Tak więc łącza mogą zmieniać się w zasobie w czasie (w oparciu o działania, które zostały już wykonane).

To pozwala nam zbudować interfejs użytkownika, który zawiera wszystkie możliwe stany, ale nie martw się, kiedy te stany staną się aktywne. Na przykład obecność rel="deposit"puszki może bezpośrednio powiedzieć interfejsowi użytkownika, kiedy można renderować make depositformularz. Co następnie pozwala użytkownikowi wprowadzić wartość i przesłać za pomocą linku.

Davin Tryon
źródło
2
Więc budując interfejs użytkownika, musimy nadal wiedzieć wszystko, co oferuje interfejs API, a następnie patrząc na te linki, jesteśmy w stanie poznać stan, w jakim znajdują się informacje na serwerze? Na przykład interfejs użytkownika wie, że można wpłacić, wypłacić, przenieść lub zamknąć (zna możliwe relacje), a następnie sprawdza, co wrócił, aby zobaczyć stan?
user1620696
1
Tak, może. Znowu zależy to od tego, jak dynamiczny chcesz to wziąć. Jak wspomnieli inni, możliwość zmiany łączy na serwerze (a nie niszczenia klientów) to kolejna zaleta. Staje się to bardzo interesujące, gdy interfejs API ma iPhone'a, Androida, Windows Phone, Mobile Web i klientów sieci Web, z których wszyscy korzystają (nie wspominając o tym, czy interfejs API został opublikowany dla innych, aby mogli budować klientów).
Davin Tryon
@ user1620696 Tak czy inaczej, powinieneś wiedzieć o tym wszystkim, zarówno przez klienta, jak i serwer, rozumiejąc rodzaj zawartości w przypadku udziału. Typ zawartości to znacznie więcej niż głupi xml lub Json. Powinieneś mieć jakieś treści typu „depozyt bankowy”, z którymi klient rozumie, jak współpracować
Cormac Mulhall
1
@ Nik spójrz na HAL, aby zobaczyć, w jaki sposób linki znajdują się w odpowiedzi.
Davin Tryon
1
tak, nadal masz problemy z kompatybilnością wsteczną. Można to rozwiązać, dołączając nagłówek wersji lub wersję do adresu URL. Ale powiedziałbym, że rozumiesz poprawnie.
Davin Tryon
3

Jak obecnie rozumiem, HATEOAS polega w zasadzie na wysyłaniu razem z każdą odpowiedzią linków z informacjami o tym, co robić dalej

HATEOAS to znacznie więcej niż tylko linki. Jest to „hyper media” jako silnik stanu aplikacji.

W opisie pominięto typ zawartości, formalną definicję hiper-mediów przekazywaną między klientem a serwerem.

HTML jest przykładem hiper-mediów i przykładem tego, dlaczego HATEOS działa. Sama strona HTML jest mechanizmem, który pozwala klientowi (tj. Użytkownikowi) poruszać się po stronie. Przeglądarka z możliwością renderowania HTML-a dla użytkownika w pełni nawigowalną stroną internetową. Nie chodzi tylko o to, że przekazuje linki do innych stron, ale przekazuje je w znaczący sposób, który nadaje kontekst linkom i w sposób, który pozwala przeglądarce zbudować nawigowalną stronę.

A co najważniejsze, przeglądarka może to zrobić dzięki ZEROWemu zrozumieniu samego serwisu. Przeglądarka zna tylko HTTP i HTML. W oparciu o to proste zrozumienie może przedstawić użytkownikowi New York Times do nawigacji.

Dzieje się tak nawet wtedy, gdy „użytkownik” jest innym programem komputerowym. Same hiper-media powinny określać kontekst nawigacji.

Cormac Mulhall
źródło
1
Czy nie oznacza to, że musisz zbudować klienta tak złożonego (i podatnego na błędy) jak przeglądarka? Elastyczność często wiąże się ze złożonością jako koszt ...
Andres F.,
@AndresF. nie oznacza to, że musisz lub powinieneś to zrobić, po prostu daje ci możliwość zrobienia tego dynamicznie, jeśli chcesz lub potrzebujesz.
Peteris,
2
@nik Pewnie. Z czubka mojej głowy wyobraź sobie, że masz usługę dostarczającą informacje o przodkach poprzez spokojny interfejs API. Masz typ zawartości, który określa format zasobu „Osoba”, który zawiera różne informacje na ich temat, ale także określa, jak wyglądają relacje, powiedz „brat” lub „siostra” lub „matka” itp. Ponieważ to hipermedia, te relacje po prostu mieć identyfikator URI innego zasobu osoby. Dość prosty klient używający czasowników HTTP i rozumiejący ten typ treści „Osoba” może poruszać się po tym interfejsie API. Powiedz, że chcesz znaleźć wszystkich bezpośrednich potomków konkretnej osoby.
Cormac Mulhall
2
@nik Ten klient musi po prostu rozumieć typ zawartości zasobu, do którego uzyskał dostęp oraz czasowniki HTTP (GET, PUT, DELETE itp.), a także można poruszać się po tym interfejsie API w celu pobierania i aktualizowania zasobów. Co ważniejsze, każdy klient, który rozumie typ zawartości, może przeskoczyć, za pośrednictwem identyfikatora URI, całkowicie na inny serwer i kontynuować działanie tak, jak było. Nie obchodzi ich, z jakim serwerem rozmawiają, dbają tylko o typ zawartości zasobu, czy rozumieją to, czy nie.
Cormac Mulhall
1
@Nik W takiej sytuacji masz serwer, który rozumie oryginalny typ treści (powiedzmy Osoba v1) i nowy typ treści (Osoba v2). Klient rozumie tylko osobę v1. Klient informuje serwer, jakie typy treści rozumie, za pomocą nagłówka Accept w HTTP. Korzystając z negocjacji zawartości, serwer określa, czy wyśle ​​to, co obsługuje klient, w którym to przypadku zwróci zasób, używając typu zawartości Osoba v1. Teraz możesz po prostu przestać obsługiwać ten stary typ zawartości i możesz wysłać klientowi błąd 406. Lepiej jednak starać się wspierać jak najwięcej.
Cormac Mulhall
2

Nie musisz budować dynamicznie generowanego interfejsu. Chociaż może być fajnie, nie jest wymagane. Jeśli nie możesz zbudować dynamicznego interfejsu, skorzystaj z łączy i gotowe. Wadą jest to, że ponownie jesteś mocno połączony z backendem i zawiesi się, jeśli coś się zmieni.

Korzystanie z dynamicznego układu może być dość proste:

links.forEach(function(link) {

  switch(link.rel) {

    case 'deposit':
      showDepositButton();
      break;

    case 'withdraw':
      loadWithdrawForm(link.href);
      showWithdrawButton();
      break;
  }

});

Zapisuje cię w kodzie klienta, takim jak:

if (balance <= 0 && negativeBalanceAllowed === false) {
  showWithdrawButton();
}

Możesz wprowadzić dozwoloną pozycję ujemną (na przykład pożyczając pieniądze) bez zmiany klienta.

Luc Franken
źródło
Jako nieco mocniejszy przykład, bank może oferować zmienne limity w rachunku bieżącym na swoich rachunkach, bez konieczności informowania strony klienta o limicie na każdym rachunku.
Bart van Ingen Schenau,
Prawidłowo możesz podjąć decyzję o limitach salda tak złożoną, jak chcesz i nadal nie musisz wprowadzać zmian w kliencie. Jeśli pójdziesz dalej z częściami REST, takimi jak typ zawartości, możesz pokazać różne widoki. Na przykład konto wygląda inaczej niż transakcja. Interesujący jest również kod na żądanie (choć niewiele wdrożony). Można to wykorzystać na przykład do estymatora pożyczki. Może nadać interfejsowi prostą funkcję kalkulatora, więc klient musi jedynie wprowadzić dane wejściowe do obliczeń. Będzie aktualizowany od zaplecza.
Luc Franken,
2
Ale zwykle klient musi wiedzieć DLACZEGO nie może się wycofać, dlatego nadal musimy wysłać do klienta ENUM lub ciąg znaków w oddzielnym polu reason. A jeśli nadal tego potrzebujemy, dlaczego nie wysłać mu innego pola boolowskiego canWithdrawzamiast linku do akcji? Kolejną zaletą jest możliwość zmiany adresu URL akcji bez dotykania klienta. Ale ... z jakiego powodu zmienić adres URL? W większości przypadków jest to również zmiana semantyczna, parametrów, kształtu zapytania / odpowiedzi itp. Tak więc musimy zmienić klienta. Wciąż tego nie rozumiem - po co HATEOAS.
Ruslan Stelmachenko