Was bringt HATEOAS auf der Client-Seite?

35

Nach meinem derzeitigen Verständnis geht es bei HATEOAS im Wesentlichen darum, zusammen mit jeder Antwort Links mit Informationen darüber zu senden, was als Nächstes zu tun ist. Ein einfaches Beispiel ist im Internet leicht zu finden: ein Bankensystem zusammen mit einer Kontoressource. Das Beispiel zeigt diese Antwort nach einer GET-Anforderung an eine Kontoressource

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>

Zusammen mit den Daten gibt es Links, die angeben, was als nächstes getan werden kann. Wenn der Saldo negativ ist, haben wir

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>

Damit können wir nur einzahlen. Das ist alles in Ordnung, wenn wir Fiddler verwenden oder Anfragen mit dem Browser stellen, können wir leicht sehen, was getan werden kann. Diese Art von Informationen ist dann nützlich, um die Funktionen der API zu ermitteln und den Server vom Client zu entkoppeln.

Der Punkt ist jedoch, dass wenn wir einen Client wie ein SPA mit Javascript oder eine Android-App oder viele andere Dinge erstellen, ich nicht sehen kann, wie HATEOAS weiterhin relevant ist. Damit meine ich Folgendes: Wenn ich das SPA in Javascript codiere, muss ich wissen, was in der API getan werden kann, um den Code zu schreiben.

Ich muss also die Ressourcen kennen, die unterstützten Methoden, was sie erwarten und was sie zurückgeben, um die Ajax-Aufrufe an den Server zu schreiben und sogar um die Benutzeroberfläche zu erstellen. Wenn ich die Benutzeroberfläche erstelle, muss ich wissen, dass man nach der Anforderung des Kontos beispielsweise Einzahlungen vornehmen kann oder dass ich diese Option auf der Benutzeroberfläche nicht bereitstellen kann. Außerdem muss ich die URI kennen, um die Einzahlung für den Ajax-Call zu tätigen.

Ich meine, wenn wir Anfragen an die API stellen, können wir die API durch Links besser erkennen und nutzen. Wenn wir jedoch einen Client erstellen, wird die App, die wir erstellen, nicht einfach die Links betrachten und dann von selbst rendern die richtige Benutzeroberfläche und machen die richtigen Ajax-Aufrufe.

Wie wichtig ist HATEOAS für die Kunden? Warum beschäftigen wir uns überhaupt mit HATEOAS?

user1620696
quelle
1
Du hast recht, aber darum geht es nicht. HATEOAS verhindert, dass Sie die URIs für die Links auf der Seite auf dem Client erstellen müssen.
James McLeod

Antworten:

24

Die App, die wir erstellen, schaut nicht einfach auf die Links und rendert dann von sich aus die richtige Benutzeroberfläche und führt die richtigen Ajax-Aufrufe aus

In der Tat ist dies genau das, was HATEOAS wird die Benutzeroberfläche geben. Nicht was möglich ist, sondern wann es möglich ist. Ein formaler HATEOAS wie HAL gibt , wie die Frage besagt, Links an, die angeben, was möglich ist. Aber wenn diese Verbindungen auftauchen , hängt vom Zustand der Anwendung. Die Links können sich also im Laufe der Zeit auf der Ressource ändern (basierend auf bereits durchgeführten Aktionen).

Auf diese Weise können wir eine Benutzeroberfläche erstellen, die alle möglichen Status enthält , sich jedoch nicht mit dem Zeitpunkt befasst, zu dem diese Status aktiv werden. Das Vorhandensein von rel="deposit"kann beispielsweise der Benutzeroberfläche direkt mitteilen, ob das Rendern des make depositFormulars in Ordnung ist . Auf diese Weise kann der Benutzer einen Wert eingeben und über den Link übermitteln.

Davin Tryon
quelle
2
Wenn wir also die Benutzeroberfläche erstellen, müssen wir noch alles wissen, was die API bietet, und dann über diese Links wissen, in welchem ​​Zustand sich die Informationen auf dem Server befinden. So weiß die Benutzeroberfläche beispielsweise, dass es möglich ist, einzuzahlen, abzuheben, zu übertragen oder zu schließen (kennt die möglichen rels), und prüft dann, was zurückgekommen ist, um den Zustand zu sehen?
user1620696
1
Ja, das könnte es. Auch hier kommt es darauf an, wie dynamisch Sie es aufnehmen wollen. Wie bereits erwähnt, ist die Möglichkeit, Links auf dem Server zu ändern (und Clients nicht zu beschädigen), ein weiterer Vorteil. Und dies wird sehr interessant, sobald Ihre API über ein iPhone, Android, Windows Phone, Mobile Web und Web-Clients verfügt, die sie alle verwenden (ganz zu schweigen davon, ob Ihre API für andere veröffentlicht wurde, auf denen Clients aufbauen können).
Davin Tryon
@ user1620696 All dies sollten Sie ohnehin wissen, indem sowohl der Client als auch der Server den Inhaltstyp verstehen, wenn die Ressource. Der Inhaltstyp ist viel mehr als nur dummes XML oder Json. Sie sollten über eine Art "Bankeinzahlung" verfügen, mit der der Kunde
vertraut ist
1
@Nik Schauen Sie sich HAL an, um ein Beispiel dafür zu finden, wie die Links in der Antwort bereitgestellt werden.
Davin Tryon
1
Ja, Sie haben immer noch Probleme mit der Abwärtskompatibilität. Dies kann gelöst werden, indem ein Versionsheader oder eine Version in die URL eingefügt wird. Aber ich würde sagen, dass Sie richtig verstehen.
Davin Tryon
3

Nach meinem derzeitigen Verständnis geht es bei HATEOAS im Wesentlichen darum, zusammen mit jeder Antwort Links mit Informationen darüber zu senden, was als Nächstes zu tun ist

HATEOAS ist viel mehr als nur Links. Es ist "hyper media" als Motor des Anwendungszustands.

Was in Ihrer Beschreibung fehlt, ist der Inhaltstyp, die formale Definition der Hyper-Medien, die zwischen Client und Server übertragen werden.

HTML ist ein Beispiel für Hyper-Media und ein Beispiel dafür, warum HATEOS funktioniert. Die HTML-Seite selbst ist die Engine, die es dem Client (dh dem Benutzer) ermöglicht, sich durch die Site zu bewegen. Ein Browser, der nur HTML-Code darstellen kann und dem Benutzer eine vollständig navigierbare Website bietet. Es ist nicht einfach so, dass es Links zu anderen Seiten übergibt, sondern es übergibt sie auf eine sinnvolle Weise, die den Links Kontext verleiht und es dem Browser ermöglicht, eine navigationsfähige Site zu erstellen.

Und am wichtigsten ist, dass der Browser dies mit ZERO im Vorfeld des Verständnisses der Website selbst tun kann. Der Browser kennt nur HTTP und HTML. Basierend auf diesem einfachen Verständnis kann es dem Benutzer die New York Times zur Navigation präsentieren.

Dies gilt auch dann, wenn der "Benutzer" ein anderes Computerprogramm ist. Die Hyper-Medien selbst sollten den Kontext der Navigation definieren.

Cormac Mulhall
quelle
1
Würde das nicht bedeuten, dass Sie einen Client erstellen müssen, der so komplex (und fehleranfällig) ist wie ein Browser? Flexibilität geht oft mit Komplexität
Andres F.
@AndresF. Dies bedeutet nicht, dass Sie dies tun müssen oder sollten , sondern bietet Ihnen lediglich die Möglichkeit, dies dynamisch zu tun, wenn Sie dies möchten oder benötigen.
Peteris
2
@nik Sicher. Stellen Sie sich auf den ersten Blick vor, Sie hätten einen Dienst, der Ahneninformationen über eine erholsame API liefert. Sie haben einen Inhaltstyp, der das Format einer 'Personen'-Ressource definiert, die verschiedene Informationen enthält, aber auch definiert, wie Beziehungen aussehen, z. B.' Bruder 'oder' Schwester 'oder' Mutter 'usw. Da diese Beziehungen einfach hypermedial sind einen URI für eine andere Personenressource haben. Ein relativ einfacher Client, der die HTTP-Verben verwendet und diesen Inhaltstyp "Person" versteht, kann durch diese API navigieren. Angenommen, Sie möchten alle direkten Nachkommen einer bestimmten Person finden.
Cormac Mulhall
2
@nik Dieser Client muss lediglich den Inhaltstyp der Ressource, auf die er zugegriffen hat, und die HTTP-Verben (GET, PUT, DELETE usw.) verstehen, und Sie können durch diese API navigieren, um Ressourcen abzurufen und zu aktualisieren. Und was noch wichtiger ist: Jeder Client, der den Inhaltstyp versteht, kann über einen URI zu einem anderen Server springen und so weitermachen, wie er war. Es ist ihnen egal, mit welchem ​​Server sie sprechen, sie kümmern sich nur um den Inhaltstyp der Ressource, verstehen ihn oder nicht.
Cormac Mulhall
1
@Nik In einer solchen Situation haben Sie einen Server, der den ursprünglichen Inhaltstyp (z. B. Person v1) und den neuen Inhaltstyp (Person v2) versteht. Der Kunde versteht nur Person v1. Der Client teilt dem Server über den Accept-Header in HTTP mit, welche Inhaltstypen er versteht. Mithilfe der Inhaltsaushandlung bestimmt der Server, ob das vom Client unterstützte Objekt gesendet wird. In diesem Fall wird die Ressource mit dem Inhaltstyp Person v1 zurückgegeben. Jetzt möchten Sie möglicherweise einfach aufhören, diesen alten Inhaltstyp zu unterstützen, und können dem Client einen 406-Fehler senden. Es ist jedoch besser zu versuchen, so viel wie möglich zu unterstützen.
Cormac Mulhall
2

Sie müssen keine dynamisch generierte Schnittstelle erstellen. Obwohl es schön sein könnte, ist es nicht erforderlich. Wenn Sie keine dynamische Schnittstelle erstellen können, verwenden Sie einfach die Links und fertig. Nachteil ist, dass Sie wieder fest mit dem Backend verbunden sind und abstürzen, wenn sich etwas ändert.

Die Verwendung des dynamischen Layouts kann übrigens recht einfach sein:

links.forEach(function(link) {

  switch(link.rel) {

    case 'deposit':
      showDepositButton();
      break;

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

});

Es speichert Sie in Ihrem Kundencode wie:

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

Sie können eine zulässige negative Position implementieren (z. B. durch Ausleihen von Geldern), ohne den Kunden zu wechseln.

Luc Franken
quelle
Als etwas stärkeres Beispiel kann die Bank variable Überziehungslimits für ihre Konten anbieten, ohne dass die Kundenseite darüber informiert werden muss, wie hoch das Limit für jedes Konto ist.
Bart van Ingen Schenau
Richtig, Sie können die Entscheidung über Saldolimits so komplex treffen, wie Sie möchten, und müssen dennoch keine Änderungen am Kunden vornehmen. Wenn Sie dies mit REST-Teilen wie dem Inhaltstyp fortsetzen, können Sie verschiedene Ansichten anzeigen. Beispielsweise unterscheidet sich ein Konto von einer Transaktion. Interessant ist auch Code on Demand (wenn auch nicht viel implementiert). Dies könnte beispielsweise für einen Kreditschätzer verwendet werden. Es kann der Schnittstelle eine einfache Rechnerfunktion geben, so dass der Client nur die Eingaben für die Berechnung implementieren muss. Es wird vom Back-End auf dem neuesten Stand bleiben.
Luc Franken
2
In der Regel muss der Kunde jedoch wissen, WARUM er nicht auszahlen kann. Daher müssen wir dem Kunden immer noch eine ENUM oder einen String in einem separaten Feld mit senden reason. Und wenn wir das noch brauchen, warum senden wir ihm nicht einfach ein anderes boolesches Feld canWithdrawanstelle eines Links zur Aktion? Ein weiterer Vorteil ist die Möglichkeit, die URL einer Aktion zu ändern, ohne den Client zu berühren. Aber .. welchen Grund, die URL zu ändern? In den meisten Fällen ändert sich auch die Semantik oder die Parameter oder die Anfrage- / Antwortform usw. Wir müssen also trotzdem den Client ändern. Also verstehe ich es immer noch nicht - was der Sinn von HATEOAS ist.
Ruslan Stelmachenko