Representational State Transfer (ReST)

https://oer-informatik.de/rest-grundlagen

tl/dr; (ca. 12 min Lesezeit): Grundlagen zur ReST, Klärung der Begriffe Ressource (Entität in ReST), Repräsentation (Darstellungsform, z.B. JSON, XML), HTTP-Methoden (GET, PUT, POST, DELETE) und deren Zuordnung zur CRUD, Eigenschaften der Methoden: safe/cacheable/idempotent, Abgrenzung URI/URL/URN, HATEOS, Hypermedia.

Verteilte Systeme

Häufig können nicht alle Dienste, die zur Erfüllung einer Aufgabe nötig sind, auf ein und dem selben Server ausgeführt werden. Wir müssen Techniken nutzen, um Aufgaben zwischen mehreren Servern zu verteilen.

Zur Maschine-Maschine Kommunikation verteilter Systeme gibt es eine ganze Reihe unterschiedlicher Spezifikationen, die sich in Architektur (Client/Server, Hub/Spoke, …), Datenformaten der Nachrichten (JSON, XML, binär), Transportschichtprotokoll (TCP oder UDP) oder der Implementierung des Nachrichtenflusses unterscheiden. Verbreitet sind Webservices wie das XML-basierte SOAP, IoT-Protokolle wie MQTT, Object-Request-Broker wie CORBA sowie eine ganze Reihe von Spezifikationen von Remote Procedure Calls (RPC) verschiedenster Hersteller.

Daneben gibt es noch eine weitere, derzeit sehr verbreitete Schnittstellen-Konzeption: Representational State Transfer (ReST) baut auf den Grundregeln des HTT-Internetprotokolls auf. Das Vokabular von ReST-Services entspricht dem des HTT-Protokolls, daher sehen wir uns zunächst die Grundlagen dieses Protokolls an.

Was ist HTTP?

Das HyperTextTransferProtocol (HTTP) definiert die Übertragung von Daten in einem Netzwerk auf der ebene der Anwendungsschicht. Wir verwenden es täglich beim surfen im Netz per Browser (daher der etwas kryptische Prefix der Internetadressen: http://). Die Nachrichtenfolge basiert auf einem einfachen Request-Response-Mechanismus: auf einen Request des Clients reagiert der Server mit einer Response. Der Aufbau beider Nachrichten für den HTTP-Standard 1.1 ist im RFC-2616 festgelegt. Die neueren Spezifikationen HTTP/2 und HTTP/3 bauen auf diesem Standard auf.

Die wesentlichen Grundbegriffe bei HTTP sind (im Schnelldurchlauf):

  • URI: Eine eindeutige Adresse, unter der bestimmte Entitäten im Netz erreichbar sind.

  • Ressourcen: Entitäten, die über das Internet zur Verfügung gestellt werden.

  • Repräsentationen: Unterschiedliche Darstellungsformen, in der eine Entität abgebildet ist (etwa JSON oder XML).

  • Methoden: Verben des HTT-Protokolls, die festlegen, was mit der Ressource geschehen darf.

  • Zusicherungen und Eigenschaften der Methoden: Garantien, die dem Nutzer gegeben werden, wenn er bestimmte Methoden ausführt.

  • Hypermedia: Querverlinkungen zwischen unterschiedlichen Ressourcen.

Das alles kennen wir bereits vom normalen Surfen durch das Netz: wir geben eine URI im Browser ein (z.B. http://www.tagesschau.de), setzen damit einen GET-Request ab (eine HTTP-Methode). Als Antwort (Response) erhalten wir eine Repräsentation der Ressource (HTML-Datei). Auf dieser finden sich weitere Links (Hypermedia). Für die Mensch-Maschine-Kommunikation (wie Surfen im Netz) wird nur ein geringer Umfang an Methoden und Repräsentationen von HTTP genutzt. Die wahre Stärke und Vielfalt entwickelt das HTT-Protokoll erst bei der Maschine-Maschine-Kommunikation mit Hilfe einer ReST-Schnittstelle.

Ressourcen

Dreh- und Angelpunkt von ReST sind die Ressourcen. Sie stellen die eigentlichen Entitäten dar, um die sich die API aufspannt. Was sagt der HTTP-Standard zur Ressourcen?

A network data object or service that can be identified by a URI(…). Resources may be available in multiple representations (e.g. multiple languages, data formats, size, and resolutions) or vary in other ways. (RFC-2616, HTTP-Standard 1.1)

Wir erreichen Ressourcen über eine URI. Ein Beispiel für eine Ressource könnte ein bestimmter Artikel in einem Onlineshop mit der folgenden URI sein:

http://meinshop.de/api/artikel/123

Für diesen Artikel können dann beispielsweise Name, Preis, Beschreibung eingegeben, geändert oder ausgegeben werden.

HTTP-Methoden

ReST nutzt die HTTP-Methoden (oft auch HTTP-Verben genannt), um die Ressourcen zu verwalten. Am wichtigsten sind diejenigen Methoden, mit deren Hilfe wir die CRUD-Operationen für unsere Entitäten abbilden können (Create, Read, Update, Delete):

Methode Beschreibung Eigenschaft
POST create
Zum Anlegen einer neuen Ressource unter einer vom Server bestimmten URI wird POST verwendet.
Für POST-Requests gelten keinerlei Garantien: es kann Seiteneffekte haben (nicht safe), ist nicht zwischenspeicherbar (nicht cacheable) und löst bei mehrfachem Absetzen des Requests mehrfache Effekte aus (nicht idempotent).
cacheable
safe
idempotent
GET read
Informationen, die durch eine URI identifiziert werden, werden in Form einer Repräsentation mit GET abgeholt. GET darf keine Seiteneffekte haben (ist also safe), muss idempotent und cacheable sein (siehe unten)!
cacheable
safe
idempotent
PUT update
Zum aktualisieren einer Ressource wird PUT verwendet. PUT ist idempotent: ändere ich die Ressource mehrfach mit gleichen Werten, bleibt der Zustand unverändert.
cacheable
safe
idempotent
DELETE delete
Zum Löschen einer Ressource wird DELETE verwendet. Auch DELETE ist idempotent.
cacheable
safe
idempotent

Darüber hinaus gibt es noch einige weitere HTTP-Methoden, die seltener von ReST-APIs implementiert werden. Am nächsthäufigsten finden Verwendung:

Eigenschaft Beschreibung Eigenschaft
PATCH update
Wenn nicht eine komplette Ressource aktualisiert wird, sondern nur einzelne Attribute, wird häufig PATCH verwendet. Es ist in der HTTP1.1 Spezifikation jedoch nicht festgelegt1 und bietet keinerlei Garantien
cacheable
safe
idempotent
HEAD read
Grundsätzlich identisch zu `GET, liefert jedoch keinen Body (Content) zurück. Kann genutzt werden, um zu überprüfen, ob der Inhalt des eigenen Caches noch akutell ist ohne die “teure” Ressource direkt zu laden.
cacheable
safe
idempotent

HTTP-Eigenschaft safe

HTTP-Methoden sind sicher (safe) wenn sie keine Seiteneffekte haben. Suchmaschinen beispielsweise crawlen das Internet über HTTP-GET-Aufrufe. Das geht gefahrlos, da GET per Spezifikation keine Seiteneffekte haben soll. Lösch- oder Erzeugungsoperationen sollten somit niemals über GET (wie z.B. einfache Links im Browser) initiiert werden! Logging gilt in diesem Zusammenhang nicht als Seiteneffekt. Der Standard HTTP1.1 spezifiziert dazu:

Implementors should be aware that the software represents the user in their interactions over the Internet, and should be careful to allow the user to be aware of any actions they might take which may have an unexpected significance to themselves or others.

In particular, the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered “safe”. […]

Naturally, it is not possible to ensure that the server does not generate side-effects as a result of performing a GET request; in fact, some dynamic resources consider that a feature. The important distinction here is that the user did not request the side-effects, so therefore cannot be held accountable for them. (RFC-2616, HTTP-Standard 1.1)

HTTP-Eigenschaft Idempotenz

Eine Operation ist dann idempotent, wenn ein mehrmaliges Aufrufen die gleichen Seiteneffekte hat wie ein einmaliges. Während ein POST-Request mit jedem Aufruf eine weitere neue Ressource erzeugt, ändert ein zweites Ausführen eines GET, PUT oder DELETE nichts am Zustand des Systems. In der HTTP-Spezifikation ist ausgeführt:

Methods can also have the property of “idempotence” in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request. The methods GET, HEAD, PUT and DELETE share this property. (RFC-2616, HTTP-Standard 1.1)

Die mit Abstand beste Erklärung für Idempotenz stammt jedoch von geek-and-poke.com:

Cartoon von geek-and-poke.com (CC BY 3.0)
Cartoon von geek-and-poke.com (CC BY 3.0)

HTTP-Eigenschaft cacheable

Die Stärke des Internets liegt auch an der Fähigkeit, Informationen - beispielsweise in Proxies - zwischenzuspeichern (Cache). Alle GET-Requests müssen die Möglichkeit bieten. Dadurch können Zugriffzeiten und Lastverteilungen im gesamten Internet optimiert werden. Der Standard legt fest:

A response is cacheable if a cache is allowed to store a copy of the response message for use in answering subsequent requests. […] Even if a resource is cacheable, there may be additional constraints on whether a cache can use the cached copy for a particular request.(RFC-2616, HTTP-Standard 1.1)

Es müssen nur dann komplette Ressourcen geladen werden, wenn sie nicht im Cache vorhanden sind oder als veraltet gekennzeichnet wurden (z.B. über die Header-Felder Expires oder Cache-Control). Mit Hilfe eines HEAD-Requests lassen sich diese Informationen abfragen, ohne dass der eigentliche Content der Ressource abgefragt werden muss.

Repräsentationen

Im Browser erhalten wir bei HTTP-GET Requests in der Regel HTML-Seiten, Bilder oder Videos als Antwort. Der HTTP-Standard sagt folgendes über die Repräsentationen:

An entity included with a response that is subject to content negotiation, as described in section 12. There may exist multiple representations associated with a particular response status. (RFC-2616, HTTP-Standard 1.1)

Im Fall der Ressource http://meinshop.de/api/artikel/123 wären denkbare Repräsentationen:

  • JSON für die Eigenschaften des Artikels (Media-Type application/json)

  • eine EDIFACT-Nachricht die die Daten für die Abrechnung auswertet (Media-Type application/EDIFACT)

  • eine XML-Datei mit allen enthaltenen Informationen (Media-Type application/xml)

Bei jedem ReST-Requests kann der Client über den Accept-Header angeben, welche Repräsentation der Ressource er gerne erhalten würde. Hierzu wird der Media-Type übergeben, zum Beispiel:

Accept: application/json

Beim Versenden von Werten wird über den Content-Type mitgeliefert, welches Format die übergebenen Daten haben. Auch hier wird der Media-Type genutzt.

Content-Type: : application/json

Es gibt eine lange Liste an Media-Types2 (vormals “Mime-Type” genannt). Selten bieten ReST APIs mehrere davon an, häufig wird ausschließlich JSON genutzt. Trotz allem: die Möglichkeit, aus unterschiedlichen Repräsentationen eine auszuwählen ist in ReST implementiert.

URN? URL? URI? Ist das alles das Gleiche?

Wenn wir eine Ressource ansprechen wollen um sie zu lesen, verändern oder zu löschen benötigen wir einen Identifikator für jede Instanz. Hierfür gibt es den Uniform Ressource Identifier, den wir beispielsweise im Internet in der Browserzeile oben eingeben. Andere sprechen in ähnlichen Zusammenhängen von URL (Uniform Ressource Locator) oder URN (Uniform Ressource Name). Sind das Synonyme oder unterscheiden sie sich? Es kursieren im Netz die verrücktesten Erklärungsversuche. Aber was sagt der Standard? Eine Definition findet sich in RFC3986 (“Uniform Resource Identifier (URI): Generic Syntax”):

A URI can be further classified as a locator, a name, or both. The term “Uniform Resource Locator” (URL) refers to the subset of URIs that, in addition to identifying a resource, provide a means of locating the resource by describing its primary access mechanism (e.g., its network “location”). The term “Uniform Resource Name” (URN) has been used historically to refer to both URIs under the “urn” scheme [RFC2141], which are required to remain globally unique and persistent even when the resource ceases to exist or becomes unavailable, and to any other URI with the properties of a name.

An individual scheme does not have to be classified as being just one of “name” or “locator”. Instances of URIs from any given scheme may have the characteristics of names or locators or both, often depending on the persistence and care in the assignment of identifiers by the naming authority, rather than on any quality of the scheme. Future specifications and related documentation should use the general term “URI” rather than the more restrictive terms “URL” and “URN” [RFC3305].

Offensichtlich will sich der Standard hier nicht festlegen, hauptsache es ist eine eindeutige Bezeichnung. URI scheint also ein Oberbegriff zu sein für URL und URN.

Unified Resource Names identifizieren eine Ressource eindeutig über den Namen, der in einem definierten Namensraum liegen darf. Einige Namensräume verwenden wir auch im Alltag, z.B.:

  • Das Buch über Design Pattern der “Gang of Four” ist eindeutig beschrieben über die URN des ISBN-Namensraums:
URN:ISBN:978-3-8266-9700-5
  • Die Norm für Qualitätskriterien und Bewertung von Softwareprodukten ist festgelegt im ISO-Namensraum:
urn:iso:std:iso:25000:-2014:ed-1:de
  • Das Dokument Request for Comments, das die URN Syntax festlegt (RFC 2141), ist eindeutig beschrieben im IETF-Namensraum:
urn:ietf:rfc:2141
  • Dokumente des IEEE-Standard, die WLAN spezifizieren, sind im IEEE-Namensraum identifizierbar unter:
urn:ieee:std:802.11:yang:{resourceIdentifier}
  • Auch für Universally Unique IDentifier (UUID) gibt es einen eigenen Namensraum (Beispiel aus UUID-RFC):
urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6

Wir nutzen URN also dazu, Ressourcen eindeutig zu beschreiben. Jede/r weiß mit der URN genau, von welcher Ressource gesprochen wird. Wir wissen damit aber nicht, wo wir sie finden. Weitere Namensräume finden sich in der Veröffentlichung der IANA zu URN-Namensräumen.

Unified Resource Locators identifizieren eine Ressource eindeutig über deren Ort. Diese Art URI ist uns sehr geläufig, daher sehe ich von weiteren Beispielen ab (insbesondere solchen, die Telefonnummer oder andere Protokolle als URI darstellen. Zum Verständnis von ReST trägt das nicht bei). Die URL ist die im Internet derzeit verbreitetste URI. Im Fall einer URI für eine ReST-API könnte sie beispielhaft so aussehen:

http://meinshop.de/api/artikel/123

Beide Varianten (URN und URL) sind Unified Resource Identifier. Denkbar, dass zukünftig Browser und andere HTTP-Clients auch in der Lage sind, URNs aufzulösen und Informationen dieser Ressourcen darzustellen. Bis dahin spielen URN für ReST jedoch keine große Rolle.

Zusammenhang URI, URN, URL
Zusammenhang URI, URN, URL

Der Aufbau einer URI wird im URI-Standard direkt für beide Komponenten gemeinsam angegeben:3

       foo://example.com:8042/over/there?name=ferret#nose
       \_/   \______________/\_________/ \_________/ \__/
        |           |            |            |        |
     scheme     authority       path        query   fragment
        |   _____________________|__
       / \ /                        \
       urn:example:animal:ferret:nose

Die bei ReST gebräuchlichen URL nutzen die oben dargestellten Kompontenen Query und Fragment nicht. Es sind URI üblich, die alle Entitäten eines Typs über die URI des Entitätstyp ansprechen:

http://meinshop.de/api/artikel

Diese URI gibt die Liste aller Artikel zurück. Sie wird auch zum Erstellen eines neuen Artikels (per POST) angesprochen.

Einzelne Entitäten werden dann direkt über die angehängte ID angesprochen:

http://meinshop.de/api/artikel/123

Hypermedia und HATEOS

ReST ist eine zustandslose API. Sämtliche Informationen, die benötigt wird, muss aus der URI hervorgehen. Aufrufe wie “nächstes Objekt” (http://beispiel.de/next_article) setzen Vorwissen voraus (nämlich den bisherigen Zustand) und sind daher nicht ReST-konform. Sie wären beispielsweise auch nicht cacheable, da jeder Aufruf etwas anderes zurückgeben müsste.

Damit wir trotzdem in ReST-APIs navigieren können ist eine weitere Eigenschaft von zentraler Bedeutung: Hypermedia. Jede ReST-Antwort und jede Ressource kann selbst Verknüpfungen (Links) zu weiteren Ressourcen enthalten. Ein Aufruf der Ressource aller Rechnungen…

http://meinshop.de/api/rechnung

…würde mir also eine Liste der URI der einzelnen Rechnungen zurückgeben. Der Aufruf einer Rechnung…

http://meinshop.de/api/rechnung/123

…beispielsweise eine Liste der enthaltenen Artikel-URI. Wir können also von Request zu Request navigieren und uns die Ressourcen selbständig erschließen.

Da diese Links bei ReST eine ähnlich große Rolle spielen wie bei Internetseiten wurde dieser Eigenschaft eigens ein Akronym gewidmet:

HATEOAS:

Hypermedia as the Engine of Application State”

Response Status Codes

HTTP-Requests antworten immer auch mit einem Statuscode. Einige Codes (wie z.B. 404 / Resource not found) begegnen uns auch im Browser immer wieder. Die relevanten Gruppen sind (wieder aus dem HTTP-Standard):

  • 1xx (Informational): The request was received, continuing process

  • 2xx (Successful): The request was successfully received, understood, and accepted

  • 3xx (Redirection): Further action needs to be taken in order to complete the request

  • 4xx (Client Error): The request contains bad syntax or cannot be fulfilled

  • 5xx (Server Error): The server is aware that it has erred or is incapable of performing the requested method.

Mit welchen Statuscodes eine ReST-API auf die jeweiligen Anfragen antworten sollte, ist ebenso im HTTP-Standard (Sektion 6.1) festgeschrieben.

Tools für ReST

Einfache GET- und POST Requests lassen sich direkt im Browser absetzten. Für die anderen Methoden benötigen wir im Browser Scriptunterstützung oder andere Tools.

Die einfachsten Tools bietet die Kommandozeile. Für Win-Clients bietet die Powershell beispielsweise das Commandlet Invoke-WebRequest, mit dem ReST-APIs angesprochen werden können.

Als Beispiel hier ein POST-Request an eine laufende ReST-API (der Übersicht halber auf mehrere Zeilen verteilt):

Es wurde eine neue Ressource angelegt. Als Ergebnis wird der Statuscode 201 (HTTP Created) und eine zugewiesene id zurückgegeben:

StatusCode        : 201
StatusDescription :
Content           : {"id":2,"firstName":"Martin","lastName":"Mustermann","street":null,"streetAdditional":null,"postalCode":null,"city":null,"country":null}
RawContent        : HTTP/1.1 201
                    Transfer-Encoding: chunked
                    Keep-Alive: timeout=60
                    Connection: keep-alive
                    Content-Type: application/json
                    Date: Tue, 06 Sep 2022 08:22:02 GMT

                    {"id":2,"firstName":"Martin","lastName...
Forms             : {}
Headers           : {[Transfer-Encoding, chunked], [Keep-Alive, timeout=60], [Connection, keep-alive], [Content-Type, application/json]...}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 136

Ein Kommandozeilentool bieten natürlich auch die *nix-Betriebssysteme (also auch OSX), hier heißt das Bordmittel cURL. Auch hierzu ein Beispielaufruf - diesmal wird eine Ressource anhand eines übergebenen JSON-Strings aktualisiert. Der Befehl ist auch hier zur Lesbarkeit auf mehrere Zeilen verteilt:

Die Antwort der ReST-API stellt cURL folgendermaßen dar:

HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 07 Sep 2020 04:50:29 GMT

{"id":2,"firstName":"Andreas","lastName":"Geändert"}

Fazit

ReST-APIs bieten die Möglichkeit, durch die Vorteile des HTT-Protokolls verteilte Systeme relativ einfach aufzusetzen. Die wesentlichen Grundlagen dabei sind:

  • Alle Ressourcen sind eindeutig über die URI identifizierbar.

  • Ressourcen können über unterschiedliche Repräsentationen verfügen - abhängig davon, was angefordert wird.

  • Der Zustand der Ressourcen ergibt sich eindeutig aus dem Request und der URI. Es gibt keine Zustände, die in Sessions oder ähnlichem gespeichert werden.

  • Über Hypermedia ist die Verknüpfung aller Ressourcen sichergestellt.

  • Die Requests enthalten in der URI keine Methode. Die Methoden werden durch die Request-Art vorgegeben. Je nach Methode genügen sie den Garantien safe, idempotent, cacheable, wie vom HTTP-Standard festgelegt.

  • Deutschsprachiges Standardwerk zu ReST: REST und HTTP (Stefan Tilkov, Martin Eigenbrodt, Silvia Schreier, Oliver Wolf), dPunkt Verlag Heidelberg, 3. Auflage, ISBN 978-3-86490-120-1

Quellen und offene Ressourcen (OER)

Die Ursprungstexte (als Markdown), Grafiken und zugrunde liegende Diagrammquelltexte finden sich (soweit möglich in weiterbearbeitbarer Form) in folgendem git-Repository:

https://gitlab.com/oer-informatik/java-springboot/rest.

Sofern nicht explizit anderweitig angegeben sind sie zur Nutzung als Open Education Resource (OER) unter Namensnennung (H. Stein, oer-informatik.de) freigegeben gemäß der Creative Commons Namensnennung 4.0 International Lizenz (CC BY 4.0).

Creative Commons Lizenzvertrag


  1. PATCH wird in einem eigenen RFC 5789 spezifiziert

  2. Die Gesamtliste der Media-Types ist von IANA auf der Internetseite https://www.iana.org/assignments/media-types/media-types.xhtml zusammengetragen worden

  3. RFC 3986, Section 3

Kommentare gerne per Mastodon, Verbesserungsvorschläge per gitlab issue (siehe oben). Beitrag teilen: