RESTful Webservices (REST API Design)

Das Schaubild eines RESTful Webservices

Neben den bekannten WS-* Stack (SOAP, WSDL, WS-* Universum) gibt es noch weitere Möglichkeiten einen Webservice zu implementieren. Dieses ist zum Beispiel der Architekturstil REST (REpresentational State Transfer). Dieser Beitrag führt in die maßgeblichen Prinzipien der RESTful Webservices ein und beschreibt das Erstellen einer REST API.

Der Architekturstil REST

Die REST Architektur wurde von Roy Thomas Fielding im Jahr 2000 in seiner Dissertation als ein Architekturstil für verteilte Hypermedia Systeme formuliert. Roy Fielding ist einer der Hauptautoren der Spezifikation des Hypertext-Transfer Protokolls (HTTP/1.1, RFC 2616). Die REST Architektur nutzt das HTTP-Protokoll vollständig – im Gegensatz zu den Webservices des WS-* Stacks, die ein SOAP over HTTP Protokoll (XML basierend) einsetzen und das unterliegende HTTP Protokoll nur rudimentär benutzen.

Die RESTful Webservices

Der Architekturstil REST wird bei der Integration oder der Kommunikation zwischen Anwendungen verwendet. Der Aufruf eines RESTful Webservices wird nicht durch einen Anwender in einem Browser ausgelöst. Obwohl es bei einem information-lieferndem Webservice per HTTP GET durchaus vorstellbar ist, die Daten als eine HTML-Seite zu präsentieren. Allerdings könnten aus einer Webanwendung heraus AJAX (Asynchronous JavaScript and XML) Aufruf gegen einen RESTful Webservice erfolgen.

Die RESTful Webservices sind Statuslos und liefern die Daten in unterschiedliche Repräsentationen (Formate) an den Aufrufer. Die Daten werden in mit einer URI eindeutig identifiziert und als Ressource bezeichnet. Durch den statuslosen Zustand der Kommunikation können alle Caching Mechanismen von HTTP-Servern (Gültigkeitszeitraum, Validieren, ETag, etc.) verwendet werden. Das ist ein wesentliches Element des REST Architekturstils.

Ressourcen und ihre Repräsentationen (REST API Design)

Was ist eine Ressource?

Eine Ressource ist eine semantische Entität und wird über eine langlebige URI (Uniform Resource Identifier, RFC 3986) identifiziert bzw. adressiert. Sie kann eine oder mehrere Repräsentationen (Datenformate, wie z. B. Text, XML, JSON, PDF, HTML, ATOM, RSS/RDF, etc.) besitzen.

Ein Beispiel ist die Abfrage einer Adresse oder Person, die als vCard (elektronische Visitenkarte, application/vcard, RFC 2426) geliefert wird.

Wie wird eine Ressource identifiziert (Aufbau der URI)?

Die ID einer Ressource, die URI, sagt nicht über die Verwendung oder eine Veränderung der Ressource aus. In der URI ist keine Informationen enthalten, die Auskunft darüber gibt, was mit der Ressource geschehen soll oder geschah.

Eine URI dient genau zur Identifizierung einer Ressource.

Durch die erste URI (1) wird der Kunden mit der Kundennummer 4711 und mit der letzten URI (3) das Produkt mit der Produktnummer 1 identifiziert. In der Mitte (2) wird der Fahrer A33 identifiziert.

  • Tipp: Die Namen oder Bezeichner im URI-Pfad in Plural angeben.

Die Namen im URI-Pfad sollten immer in Plural angegeben werden. Dieses ist für Programmierer der REST API einfacher umzusetzen. Werden diese URIs in einer Liste aufgeführt und sortiert, dann stehen die zusammengehörigen URIs zusammen.

Der hierarchische Aufbau einer URI ist nicht notwendig. Eine URI muss im Wesentlichen eine Ressource eindeutig identifizieren, dieses kann durchaus kryptisch erfolgen.

  • Tipp: Keine Dateierweiterung in die URI.

Bei klassischen Webanwendungen werden Downloads überwiegend mit Links auf Dateien angeboten. Eine REST API kennt keine künstlichen Dateierweiterungen in der URI. Das Format der Antwort wird in dem Header-Feld Content-Type kommuniziert.

Tipps für das URI-Design

In diesem Kapitel sind einige Tipps für den Entwurf von URIs für eine REST API.

  • Tipp: URIs ohne abschließenden Schrägstrich.

Eine URI sollte nicht mit einem Schrägstrich  / enden. Dieses zusätzliche Zeichen fügt der URI keinen semantischen Wert hinzu und sollte weggelassen werden.

Klassische Webanwendungen werden die folgenden URIs nicht unterscheiden. In einer REST Architektur stellen die unterschiedlichen URIs zwei verschiedenen Ressourcen dar.

Eine fehlertolerante Schnittstelle leitet die zweite URI (2) auf die erste URI (1) um.

  • Tipp: Bindestriche erhöhen die Lesbarkeit einer URI.

In einer URI können Bindestriche  - verwendet werden, um die Lesbarkeit von URIs zu verbessern.

Leerzeichen und Unterstriche in einem Namen oder Bezeichner sollten durch Bindestriche ersetzt werden.

  • Tipp: Keine Unterstriche in der URI verwenden.

Eine URI wird in Browsern oder Editoren oft unterstrichen dargestellt. Dadurch können Unterstriche _ nicht erkannt und sollten durch Bindestriche ersetzt werden.

Die eindeutigen Schlüssel der Datenbank können Teil der URI sein. Allerdings sollte einer Ressource keine direkte Entität aus der Datenbank entsprechen. Sondern aus einem serviceorientiertem Entwurfes oder einem API-Design hervorgehen.

Die folgende URI ist ungültig, falls sie keine einzelne Ressource identifiziert, sondern eine Menge von Ressourcen.

Die folgende URI ist gültig, wenn sie eine Liste von gleichen Ressource identifiziert und die URI die Liste als Ressource referenziert.

Der Unterschied der beiden URIs liegt in der Bezeichnung des Ergebnisses. Die Liste von gleichen Ressourcen ist wiederum eine Ressource.

  • Tipp: Eine URI sollte kleingeschrieben werden.

Um Verwechselung von URIs zu vermeiden, sollte keine Großschreibung verwendet werden.

Das Protokoll und der Hostname in einer URL dürfen großgeschrieben werden – während beim Pfad zwischen Groß- und Kleinschreibung unterschieden wird. Aber auch das sollte unterlassen werden.

Was sind verschachtelte Ressourcen?

Die Ressourcen können verschachtelt (nested resources) werden. Die verschachtelten Ressourcen sind eng gekoppelte Ressourcen im Sinne von Eltern-Kind-Beziehung (1:N). Die Kinder sind an ihren Eltern gebunden, so dass ihre Verwendung ohne Eltern keinen Sinn macht.

  • Tipp: Eine hierarchische Beziehung wird in der URI durch einen Schrägstrich angezeigt.

Die Verschachtelung oder Hierarchie der Ressourcen, wird in der URI mit einem Schrägstrich  / ausgedrückt. Dieses erhöht die Übersichtlichkeit wie auch die Verständlichkeit der URI und beeinflusst die Identifizierung nicht.

In diesem Beispiel wird die Bestellung mit der Nummer 1 des Kunden mit der ID 4711 referenziert.

URIs mit Query-Parametern

Wenn eine URI eine Ressource identifiziert, die wiederum eine Liste von Ressourcen darstellt, können Query-Parametern zum Einsatz kommen.

Query-Parameter für die Suche (Searching)

Die Suche soll die Anzahl der abgefragten Ressourcen in der zurückgegebenen Liste einschränken. Dazu wird ein Query-String angegeben. Dessen Syntax eine ungefähre Übereinstimmung in den Ressourcen ermöglicht.

Query-Parameter für das Filtern (Filtering)

Das Filtern soll, wie die Suche, die Anzahl der abgefragten Ressourcen in der zurückgegebenen Liste einschränken. Dazu werden einige Attribute der Ressourcen mit erwarteten Werten angegeben. Mehrere Werte werden mit Komma getrennt.

Query-Parameter für das Sortieren (Sorting)

Das Sortieren soll die Reihenfolge der abgefragten Ressourcen in der zurückgegebenen Liste beeinflussen. Der Sortierparameter enthält die Namen der Attribute, nach denen sortiert wird, getrennt durch ein Komma. Zusätzlich kann mit die Sortierung „+“ (Aufsteigend, Ascending) oder „-“ (Absteigend, Descending) gesteuert werden.

Query-Parameter für die Paginierung (Paging)

Die Paginierung begrenzt die Anzahl der abgefragten Ressourcen in der zurückgegebenen Liste. Dazu kann die Liste in Seiten (Page) zerstückelt oder die Anzahl der Treffer (Limitation) limitiert werden.

Query-Parameter für das Selektieren von Feldern

Mit diesem Parameter kann die Menge der zurückgelieferten Daten verringert werden. Dazu werden einzelne Attribute aus den Ressourcen ausgegrenzt. Mehrere Attribute werden mit Komma getrennt.

Versionierung einer Ressource (URI Versioning)

Wie werden verschiedene Versionen von Ressourcen unterschieden? Hier bieten sich mehrere Strategien (API Strategy) an. Die Auswahl der Versionierungsstrategie sollte vor dem Einsatz der REST API festgelegt werden. Eine nachträgliche Änderung ist meistens mit erheblichen Aufwänden verbunden. Vor allem, wenn sich bestehende bzw. permanente URIs ändern.

Zusätzlich müssen die folgenden Teile der Versionsinformationen betrachtet werden:

  • Major (Hauptversion)
  • Minor (Unterversion)
  • Patch (Bugfix)

Wann ist die Rückwärtskompatiblität einer Version gebrochen? Die Antwort auf diese Frage ist wichtig, wenn Ressourcen gecacht werden sollen. Da die verschiedenen Versionen eindeutig unterschieden werden müssen.

Einbetten der Version in die Basis-URI

Die Version wird Teil der Basis-URI (Base-URI).

Konsequenzen:

  • Die URI ist von einem API Gateway einfach umzuleiten.
  • Die Änderung der Version verhindert eine permanente URL.
    Eine Versionierung einer Ressource bedeutet nicht die Änderung ihrer Identität, sondern eine Änderung in der Darstellung. Die URI und ihre Identität sollte dieselbe bleiben.
  • Wenn eine Version nicht mehr verwendet werden darf, muss beim Zugriff auf diese URI eine Umleitung auf eine gültige Ressource erfolgen. Dieses kann mit einem HTTP Statuscode 3xx stattfinden. Leider kann die referenzierte Ressource eine geänderte Semantik besitzen.
  • Die Ressourcen mit diesen URIs können gecacht werden.
  • Wenn eine Ressource eine neue Version benötigt, bekommen alle Ressourcen unter dieser Basis-URI eine neue Version (Siehe die nächste Konsequenz).
  • Die URIs aus dem Beispiel identifizieren unterschiedliche Ressourcen, die ggf. gleich sind.
    • Bei der Beispiel URI (1) ist es unklar, welche Version die Ressource besitzt.
    • Die Beispiel URI (2) und (3) zeigen auf die gleiche Ressource, besitzen aber eine unterschiedliche Identität.
    • Die Beispiel URI (4) und (3) können auf die gleiche Ressource zeigen, wenn die Version durch eine völlig andere Ressource erzwungen wurde (Siehe vorherige Konsequenz).
  • Wenn eine URI auf eine verschachtelte Ressource zeigt, müssen mehrere Versionen in der URI angegeben werden.
    https://api.frank-rahn.de/v1/customers/4711/v1.1/addresses/1

Einbetten der Version mit Query-Parameters

Die Version ist in einem Query-Parameter enthalten.

Neben den im vorherigen Kapitel betrachteten Konsequenzen, zeigen sich zusätzlich die folgenden Konsequenzen.

Konsequenzen:

  • Ein Query-Parameter steuert gewöhnlich die Suche bzw. Abfrage und nicht die Herausgabe einer einzelnen Ressource.
    Mit einem Query-Parameter kann die Herausgabe einer Liste von Ressourcen gesteuert werden.
  • Typischerweise wird eine Ressource (eine Liste von …), in deren URI ein Query-Parameter enthalten, ist nicht gecacht.
  • Die URIs aus dem Beispiel identifizieren unterschiedliche Ressourcen, die ggf. gleich sind.
    • Bei der Beispiel URI (5) ist es unklar, welche Version die Ressource besitzt.
    • Die Beispiel URI (6) und (7) zeigen auf die gleiche Ressource, besitzen aber eine unterschiedliche Identität.
    • Die Beispiel URI (8) und (7) können auf die gleiche Ressource zeigen, wenn diese Version durch eine völlig andere Ressource erzwungen wurde.

Einbetten der Version in den MIME-Typ (Media Type Versioning)

Die Version ist Teil des MIME-Typs bzw. Media-Types. Dazu wird ein eigener MIME-Typ (RFC 6838: VND Content Type) definiert, der die Version enthält. Dieser MIME-Typ wird jeweils in der Anfrage im HTTP-Header Feld Accept und in der Antwort im HTTP-Header Feld Content-Type mitgegeben.

Diese MIME-Typen können bei der IANA (Internet Assigned Numbers Authority) registriert werden: IANA-Application for a Media Type.

Neben den im vorherigen Kapitel betrachteten Konsequenzen, zeigen sich zusätzlich die folgenden Konsequenzen.

Konsequenzen:

  • Die Änderung der Version verhindert nicht eine permanente URL.
    Die URI aus den vorhergehenden Beispielen erzeugten immer eine neue Identität. Dieses ist bei dieser Variante nicht der Fall. Jede existierende URI zeigt immer auf die gleiche Ressource.
  • Wenn eine Ressource eine neue Version benötigt, muss nur ein neue MIME-Typ verwendet oder definiert werden.
    Alle anderen Ressourcen unter der gleichen Basis-URI sind nicht betroffen.
  • Die URI für eine verschachtelte Ressource wird klarer, da sie keinerlei Versionen enthält.
    https://api.frank-rahn.de/customers/4711/addresses/1
    Der MIME-Typ betrifft die konkret zurückgelieferte Ressource.
  • Das Cachen der Ressource ist anspruchsvoller, aber möglich.
  • Der MIME-Typ beschreibt normalerweise das Format und nicht die Version der Ressource.
  • Die Standard MIME-Typen werden nicht verwendet.
    Das kann zu Problemen führen, da einige Anwendungen mit spezifischen MIME-Types nicht umgehen können. Aber ein spezifischer MIME-Typ kann semantische Informationen und Hinweise enthalten. Die bei der Verarbeitung der Ressource hilfreich sein können.

Erweiterung von eingebundene Ressourcen (Nested Resource Expansion)

Wenn eine Ressource abgefragt wird, kann sie untergeordnete Ressourcen beinhalten.

In diesem Beispiel werden die Autodaten nur verlinkt und müssen in einer zweiten Abfrage nachgelesen werden. In einigen Fällen werden die Autodaten aber direkt benötigt. Dann sollen diese in einer einzelnen Abfrage gelesen werden (Eager Loading). Dazu steht der _expand Parameter zu Verfügung.

In folgendem Beispiel werden die Autodaten direkt durch den _expand=car Parameter mitgeladen.

Dieses reduziert die Anzahl der API Aufrufe sowie den Traffic zum API Server.

Weitere Beispiele

Die Content Negotiation

Eine alternative Repräsentation einer Ressource wird durch die Content Negotiation zu Verfügung gestellt.

Die Antwort einer REST Anfrage kann auf unterschiedlichen Content Anforderungen reagieren. Dazu wird das HTTP-Header Feld Accept: text/plain ausgewertet und die Repräsentation in gewünschten Format in der Antwort (HTTP-Header Feld Content-Type: test/plain) berücksichtigt werden. Allerdings ist zu Beachten, dass diese Anforderung als ein Wunsch betrachtet wird und die Antwort anders aussehen kann.

Ein detailliertes Beispiel ist im Abschnitt Content Negotiation zu finden.

Hypermedia (Verlinkung)

Unter REST werden die Verweise (Links) auf andere Ressourcen mit URIs dargestellt. Diese Verweise werden auch mit Hyperlinks, Hypermedia, Verlinkung oder als Verknüpfung bezeichnet.

Mit diesen URIs kann direkt zwischen den Ressourcen navigiert werden. Zusätzlich können z. B. Distributed Caching realisiert werden, welche erst durch die URIs und die Hyperlinks möglich sind.

Diese Beschreibung von Services kann auch im HTTP Header (RFC 5988 – Web Linking) platziert werden.

Wobei diese Möglichkeit meistens bei Navigation bei Listen angewendet wird.

Gleichförmige (uniforme) Schnittstellen

Der Architekturstil REST vereinheitlicht (uniforme) die Schnittstellen der Ressourcen auf eine überschaubare und – bezüglich des zu erwartenden Verhaltens – standardisierte Menge von Aktionen.

Diese Aktionen sind Teil des Anwendungsprotokolls HTTP/1.1 bzw. HTTPS (RFC 2616).

HTTP Methoden

Zur Zeit werden im Internet nur die HTTP Methoden GET und POST genutzt, da nur sie von den Browsern unterstützt werden.

Aber es gibt noch weitere HTTP Methoden, wie z. B. PUT und DELETE, die in einer REST Architektur verwendet werden können. Diese HTTP Methoden werden auch Verben oder Operationen genannt.

Die Eigenschaften von HTTP Methoden

  • safe
    Der Aufruf dieser Operation hat keine Nebenwirkungen, d. h. die Ressource erfährt durch den Abruf keine Änderung. Das heißt aber nicht, dass der Webservice intern eine Zustandsänderung vorgenommen hat. Dieses können Logeinträge oder das Fortschreiben von statistischen Aufzeichnungen sein. Wichtig aus Sicht des Architekturstils REST ist es, dass für den Aufrufer die Ressource sich nicht geändert hat.
  • idempotent
    Das mehrfache Aufrufen dieser Operation liefert immer das gleiche Ergebnis.
    Mathematisch: ƒ(ƒ(x)) = ƒ ∘ ƒ(x) = ƒ(x) 😉
    Wenn nun der Aufrufer keine Antwort auf eine Anfrage erhalten hat, kann er diese Anfrage bei idempotenten Operationen einfach wiederholen. Er muss nicht prüfen, ob die Operation schon verarbeitet worden ist, das muss er nur bei nicht idempotenten Operationen.

HTTP Methode GET

Die Anforderung einer Ressource, die durch eine URI identifiziert wird, ohne das die Ressource dadurch eine Veränderung erfährt. Der Webservice liefert die Repräsentation einer Ressource.

Diese HTTP Methode GET ist safe und idempotent.

Querys dürfen nur verwendet werden, wenn das Ergebnis eine eindeutige identifizierte Ressource ist.

Dieses ist meistens der Fall, wenn das Ergebnis selbst als Ressource gewertet wird, z. B. eine Liste von Ressourcen oder das Ergebnis einer Berechnung unter der Beachtung der Eigenschaften safe und idempotent.

Der folgende Aufruf ist nicht zulässig, da dieser Aufruf nicht safe und nicht idempotent ist. Wird diese Anfrage wiederholt an einen Webservice gesendet, so unterscheiden sich im folgenden Beispiel die Antworten.

Durch die Eigenschaften safe und idempotent können Bookmarks bzw. Caches relativ einfach aufgebaut werden, da der wiederholte Aufruf keinen Schaden anrichten kann. Die Verantwortung dazu liegt nicht bei Aufrufer, sondern ausschließlich beim Provider.

HTTP Methode PUT

Die Anfrage der HTTP Methode PUT aktualisiert die bestehende identifizierte Ressource mit den mitgelieferten Daten. Sollte die Ressource noch nicht existieren, wird sie unter der URI angelegt.

Die Ressource wird vom Consumer in einer gültigen Repräsentation gesendet und ersetzt die bestehende Ressource.

Die HTTP Methode PUT ist idempotent.

HTTP Methode PATCH

Die Anfrage der HTTP Methode PATCH modifiziert nur einen Teil der angegebenen Ressource. Gegenüber der HTTP Methode PUT wird die Ressource nicht komplett überschrieben. Diese HTTP Methode ist im RFC 5789 – PATCH Method for HTTP beschrieben.

Die HTTP Methode PATCH ist weder safe noch idempotent.

HTTP Methode DELETE

Das Löschen bzw. das Entfernen der identifizierten Ressource. Falls die Ressource nicht existiert, wird kein Fehler ausgelöst, da das gewünschte Ergebnis schon erreicht ist.

Nach dem Verarbeiten der HTTP Methode DELETE liefert die HTTP Methode GET ein HTTP/1.1 404 Not Found.

Ob die Ressource tatsächlich aus der Datenbank gelöscht oder nur als gelöscht bzw. storniert markiert wurde, liegt in der Verantwortung des Webservices bzw. der zugrundeliegenden Fachlichkeit. Die Ressource darf nur nicht mehr unter der ursprünglichen URI geliefert werden.

Die HTTP Methode DELETE ist idempotent.

Das mehrfache Löschen darf keinen Fehler liefern und die Ressource darf von außen nicht mehr erreicht werden.

HTTP Methode POST

Eine oder mehrere Ressourcen erzeugen, deren URIs noch nicht bekannt sind bzw. eine unbestimmte Menge von Ressourcen ändern oder löschen. Die zugehörigen Daten hängen der Anfrage an. Durch die folgende Anfrage wird eine neue Ressource erzeugt und die identifizierende URI in der Antwort per Location Attribut zurückgegeben.

Diese HTTP Methode POST bietet die meiste Flexibilität und kann bzw. darf Seiteneffekte haben, da sie weder safe noch idempotent ist.

Der Absender hat eine gewisse Verantwortung, da die HTTP Methode POST keine Garantien liefert. Der Absender sollte also wissen, was er anstellt.

HTTP Methode HEAD

Die HTTP Methode HEAD fragt den HTTP-Header zu der identifizierten Ressource ab. Diese Anfrage liefert den gleichen Header, wie die HTTP Methode GET, nur ohne Daten.

Die HTTP Methode HEAD ist safe und idempotent.

HTTP Methode OPTIONS

Die HTTP Methode OPTIONS prüfen, welche HTTP Methoden auf der identifizierten Ressource zur Verfügung stehen.

Die HTTP Methode OPTIONS ist idempotent.

HTTP Methode TRACE

Die HTTP Methode TRACE liefert die Anfrage so zurück, wie der Server sie empfangen hat. So kann überprüft werden, ob und wie die Anfrage auf dem Weg zum Server verändert worden ist.

Die HTTP Methode TRACE ist idempotent.

HTTP Methode CONNECT

Diese HTTP Methode CONNECT wird von Proxyservern implementiert, die in der Lage sind, SSL Tunnel zur Verfügung zu stellen.

HTTP Statuscodes

Die Antwort eines RESTful Webservices beinhaltet einen HTTP Statuscode und ggf. die angeforderte Ressource. In den folgenden Kapiteln werden die wichtigsten Statuscodes für RESTful Webservices beschrieben.

HTTP Statuscodes 2xx

Mit einem HTTP Statuscode aus der 200-Gruppe wird ein Erfolg signalisiert.

  • 200 OK
    Signalisiert den Erfolg eines Zugriffes oder Änderung.
  • 201 Created
    Bestätigt das Anlegen einer Ressource.
  • 204 No Content
    Bestätigt eine Änderung, liefert aber keine Daten zurück.

HTTP Statuscodes 3xx

Die HTTP Statuscode aus der 300-Gruppe leiten die Bearbeitung an den aufrufenden Client zurück.

  • 301 Moved Permanently
    Die Ressource hat eine andere Identität angenommen. Die neue URI befindet sich im HTTP-Attribut Location.
  • 303 See Other
    Verweis auf eine andere Ressource. Diese URI befindet sich im HTTP-Attribut Location.

HTTP Statuscodes 4xx

Mit einem HTTP Statuscode aus der 400-Gruppe signalisiert der Webservice, dass er die Anfrage nicht interpretieren oder durchführen konnte. Wobei der Fehler meistens durch den aufrufenden Client ausgelöst wird.

  • 400 Bad Request
    Die Anfrage konnte vom Webservice aufgrund einer fehlerhaften Syntax nicht verstanden werden. Der Client muss die Anfrage korrigieren.
  • 401 Unauthorized
    Die Anfrage enthielt keine Informationen zur Authentifizierung oder mit den gelieferten Informationen konnte keine Authentifizierung durchgeführt werden.
  • 403 Forbidden
    Die Ausführung der Anfrage wurde wegen fehlender Berechtigungen verweigert.
  • 404 Not Found
    Die URI ist ungültig. Sie referenziert keine Ressource.
  • 405 Method Not Allowed
    Die URI referenziert eine bekannte Ressource, aber die Methode kann auf diese Ressource nicht angewendet werden.
  • 409 Conflict
    Die Anfrage wurde unter einer falschen Annahmen gestellt. Bei PUT: Die Ressource wurde zwischenzeitlich geändert.
  • 410 Gone
    Die Ressource war unter der URI zu finden, wird aber nicht mehr bereitgestellt.
  • 412 Precondition Failed
    Eine in der Anfrage übertragene Voraussetzung wurde nicht erfüllt.
  • 415 Unsupported Media Type
    Der Content einer Anfrage wurde mit einem nicht erlaubten Inhalt übertragen.
  • 422 Unprocessable Entity
    Der Content der Anfrage konnte nicht verarbeitet werden, z. B. durch semantische Fehler.

HTTP Statuscodes 5xx

Ein HTTP Statuscode aus der 500-Gruppe zeigt einen Fehler im Service an.

  • 500 Internal Server Error
    Ein allgemeiner Fehler im Webservice oder Server ist aufgetreten.

Die Beschreibungen der restlichen Statuscodes gibt es bei der Wikipedia.

Content Negotiation

Die Antwort auf eine REST Anfrage kann unterschiedliche Repräsentationen bzw. Content Formate liefern. Dazu wird das HTTP-Header-Feld Accept ausgewertet und aus dieser Wunschliste eine Repräsentation für die Antwort (HTTP-Header-Feld: Content-Type) ausgewählt. Dieser Vorgang wird Content Negotiation genannt. Hier entscheidet letztendlich der RESTful Webservice, welche Repräsentation er liefert.

Dabei stehen alle möglichen MIME-Typen zu Verfügung ( text/plain, text/html, text/xml, text/rdf, text/rss, text/x-vcard, application/xml, application/json, application/pdf, …).

In der Form application/vnd.frankrahn.drivers+xml kann auf einen nicht standardisierten XML MIME-Typ verwiesen werden.

Syntax := "application/vnd.", Hersteller, ".", XML-Schema, "+xml";

Im folgenden Beispiel kann eine XML- oder eine HTML-Repräsentation in der Antwort geliefert werden, dabei ist die XML-Repräsentation höher priorisiert ( q=1.0) und die Version ( schemaVerion=1.1) des zu verwendenden XML-Schemas festgelegt.

Der RESTful Webservice liefert die angeforderte Ressource als XML-Repräsentation.

Mit der folgenden Antwort zeigt der RESTful Webservice an, dass er die Ressource nicht in einer der gewünschten Repräsentationen liefern kann.

Distributed Caching (Validation/Expiry)

Um die Effizienz von Anwendungen zu steigern, werden häufig Caches eingesetzt. Bei einer REST Architektur können die Ressourcen mit etablierten Verfahren des Anwendungsprotokolls HTTP gecacht werden.

Dazu bietet das HTTP-Protokoll einige Attribute im Zusammenhang mit dem Distributed Caching an:

  • Last-Modified: Zeitstempel
    Wird vom Webservice in der Antwort geliefert und ermöglicht das Caching erst.
  • If-Modified-Since: Zeitstempel
    Wird bei einer erneuten Anfrage gesetzt und nur falls die Ressource nach diesem Datum verändert worden ist, wird sie auch gesendet.
  • ETag: "Entity-Tag"
    Wird vom Webservice mit der Antwort geliefert.
  • If-None-Match: "Entity-Tag"
    Wird bei einer erneuten Anfrage gesetzt und falls der aktuelle Entity-Tag der Ressource nicht passt, wird sie gesendet.

Im folgenden Beispiel wird eine Ressource abgefragt …

… und auch erfolgreich geliefert.

In einer spätereren Abfrage der gleichen Ressource wird das HTTP Attribut If-Modified-Since mitgeliefert …

… und die Antwort liefert die angeforderte Ressource nicht mehr, da sie aktuell ist.

Dieses Verfahren wird erst durch die Eigenschaften safe und idempotent der HTTP Methode GET ermöglicht, da der Abruf einer Ressource, die Ressource selber, nicht verändern darf.

Asynchrone Kommunikation

Standardmäßig ist die Kommunikation mit dem HTTP Protokoll durch den Ablauf des Request/Response Zyklus synchronisiert. Allerdings kann durch den HTTP Statuscode HTTP/1.1 202 Accepted und der Rückgabe einer URI im HTTP Attribut Location für das Ergebnis eine asynchrone Kommunikation aufgebaut werden.

Der HTTP Statuscode besagt, dass die Anfrage zu einem späteren Zeitpunkt bearbeitet wird und unter der angegebenen URI abgeholt werden kann.

Die Antwort enthält einen Verweis auf die erzeugte Ressource.

Die erfolgreiche Ausführung des Webservices wird allerdings nicht garantiert. Eine vorschnelle Abfrage GET /drivers/4712 HTTP/1.1 wird ein HTTP/1.1 404 Not Found liefern.

Reliable Messaging

Wenn eine Anfrage an einen Service-Provider gesendet wird, aber nie eine Antwort zurückkommt, kann man sich nicht sicher sein, dass die Anfrage tatsächlich angekommen ist. Eine Lösung kann durch das wiederholte Senden erreicht werden. Dieses kann bei idempotenten HTTP Methoden ohne Bedenken durchgeführt werden. Aber bei den HTTP Methoden, die nicht idempotent sind, müssen zusätzliche Mechanismen (z. B. Message-Id, Zeitstempel, …) angewendet werden, so dass der Service-Provider doppelte Anfragen erkennen kann.

Cookies

Als Cookies werden Textinformationen bezeichnet, die von Webserver auf dem Computer des Benutzers über den Browser beständig gespeichert werden. Darin werden z. B. Passwörter und Angaben über den aktuellen Benutzer abgelegt. In einer späteren Sitzung werden die Cookies direkt an den Webserver gesendet.

Die Cookies sind in einer REST Architektur nur zulässig, wenn sie allgemeine Informationen, wie z. B. Tokens, Tickets oder Session-Ids, bei Aufrufe von Webservices transportieren.

Redirection, Compression, Chunking

Die HTTP Eigenschaft Redirection leitet mit einem HTTP Statuscodes 3xx an eine andere URI weiter. Diese Umleitung kann permanent sein oder zeitlich begrenzt.

Durch die HTTP Eigenschaft Compression kann der Client eine Kompression der Antwort wünschen. Er liefert in der Anfrage im HTTP Attribut Accept-Encoding die möglichen Komprimierungsverfahren mit. Der Webservice kann sich ein Verfahren aus der Liste aussuchen und verwenden. Dieses zeigt er im HTTP Attribut Content-Encoding an. Falls er kein geeignetes Verfahren findet, komprimiert er die Antwort nicht.

Die HTTP Eigenschaft Chunking teilt eine Anfrage oder Antwort in mehrere Teile auf. Dieses wird mit dem HTTP Attribut Transfer-Encoding: chunked angezeigt. Durch das Aufteilen können große Datenmengen besser versendet werden. Dieses Verfahren kann auch für Streaming verwendet werden, wenn ein kontinuierlicher Fluss von Daten (Datenstrom) gesendet werden muss.

Beispiele von RESTful Webservice Schnittstellen

Die Schnittstellen eines RESTful Webservices müssen formal definiert werden. Dieses kann beispielsweise über eine WSDL, ein XML Schema (XSD) oder eine beliebige Beschreibungssprache erfolgen.

Im folgenden Beispiel wird die RESTful Webservice Schnittstelle einer Kundenverwaltung dargestellt.

Ein weiteres Beispiel ist der Beitrag Spring mit RESTful Webservice.

Schnittstelle zu den Kunden
URI /customers
POST Erzeuge einen neuen Kunden.
GET Liefert eine Liste mit alle Kunden auf. Die Parameter beeinflussen das Ergebnis und können miteinander kombiniert werden.

Query-Parameters:

  • search={Zeichenkette}
    Liefere nur die Kunden, die dem Suchkriterium entsprechen (Filter).
  • state=open-orders
    Liefere nur die Kunden mit offene Bestellungen (Filter).
  • keys={Liste von Kundennummern}
    Liefert eine Liste von Kunden zurück, deren Kundennummer in der Komma separierten Liste enthalten sind (Filter).
  • page={Seitenummer: 1}
    Liefere nur die angegebene Seite mit Kunden (Pagination).
  • count={Anzahl: 20}
    Legt die Anzahl der Treffer pro Seite fest (Pagination).
  • sort={Sortierung}
    Sortiere die Kunden nach dem angegebenen Kriterium (Sortierung).
  • fields={Liste von Felder}
    Schränke die zurückgelieferten Felder des Kunden ein (Felder).
PUT
DELETE
HEAD Liefere die Anzahl aller Kunden.
Schnittstelle zu einem bestimmten Kunden
URI /customers/{Kundennummer}
POST
GET Liefere den Kunden mit der Kundennummer.
PUT Ändere den Kunden mit der Kundennummer.
DELETE Lösche den Kunden mit der Kundennummer.
HEAD
Schnittstelle zu den Bestellungen eines bestimmten Kunden
URI /customers/{Kundennummer}/orders
POST Erzeuge eine neue Bestellung des Kunden mit der Kundennummer.
GET Listet alle Bestellungen des Kunden mit der Kundennummer auf.
PUT
DELETE Lösche alle Bestellungen des Kunden mit der Kundennummer.
HEAD Liefere die Anzahl aller Bestellungen des Kunden mit der Kundennummer.
Schnittstelle zu einer einzelnen Bestellung eines bestimmten Kunden
URI /customers/{Kundennummer}/orders/{Bestellungsnummer}
/orders/{Bestellungsnummer}
POST
GET Liefere die Bestellung des Kunden.
PUT Ändere die Bestellung des Kunden.
DELETE Lösche die Bestellung des Kunden.
HEAD
Schnittstelle zu einer speziellen Bestellung eines Kunden
URI /customers/{Kundennummer}/orders/date/{Bestellungsdatum}
POST
GET Liefere die Bestellungen des Kunden mit dem Datum.
PUT
DELETE
HEAD

Unter dem Link URI Template (RFC 6570) finden Sie eine Beschreibung, wie URIs mit Variablen zu definieren sind.

Zustandslose Kommunikation

Die Kommunikation mit einem RESTful Webservice erfolgt immer zustandslos, d. h. der Server verwaltet keinen Kontext über die Interaktion mit einem Aufrufer. Dadurch ergeben sich erhebliche Vorteile für die Skalierung und Ausfallsicherheit solcher Systeme, da diese Systeme auf mehrere Server verteilt werden können. Es können auch zusätzliche Dienste, wie HTTP-Proxies oder Browser-Cache, für die Steigerung der Performanz dazwischen geschaltet werden.

Es wird zwischen den zwei Zuständen Anwendungs- und Ressourcenzustand unterschieden.

Der komplexe Anwendungszustand existiert nur auf dem Client. Durch eine Repräsentation einer Ressource wird der Client in einen Anwendungszustand versetzt.

Der Zustand der Ressource wird ausschließlich auf dem Server verwaltet. Es erfolgt kein Abgleich zwischen den Zuständen. Der Server verwaltet keine speziellen Daten (z. B. im Session-Kontext per Cookies) zu einem Client. Dieser muss bei einer Anfrage alle notwendigen Daten mitgeben oder die Daten (z. B. ein Warenkorb) werden in einer eigenen (temporären?) Ressourcen zwischen gespeichert.

Somit kann ein Server zwischen zwei Aufrufen durch gestartet werden, ohne dass dieses eine Auswirkung hat oder eine Behinderung darstellt.

Die Literaturempfehlung

Frank Rahn

Frank Rahn ist Softwarearchitekt. Er unterstützt bei der Konzeption von Softwarearchitekturen mit Java-Technologie. Folge Sie ihm auf Facebook, Twitter oder Google+.

Benötigen Sie Unterstützung? Kontaktieren Sie ihn.

Hat Ihnen dieser Beitrag gefallen? Wir würden uns über Ihren Kommentar freuen! Bitte verwenden Sie Ihren bürgerlichen Namen und eine E-Mail-Adresse mit Gravatar.

Letzte Artikel von Frank Rahn (Alle anzeigen)

0 Kommentare

Dein Kommentar

Want to join the discussion?
Feel free to contribute!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.