Artikel

 
Februar 2009 | Artikel

REST - Der bessere Web Service? Fortsetzung, Teil 2

Teil 1   Teil 2   Teil 3   

Einheitliche Schnittstelle

Vielleicht die ungewohnteste Restriktion des REST-Ansatzes ist die einheitliche ("uniforme") Schnittstelle. Sie ist eine logische Konsequenz aus dem Anspruch, Anwendungen in ein Web von vernetzten Ressourcen zu transformieren. REST postuliert, dass jede Ressource die gleichen Operationen unterstützen muss. Im HTTP-Protokoll wird diese allgemeine Schnittstelle zu den bekannten Methoden GET, PUT, POST und DELETE (sowie u.a. den weniger bekannten HEAD und OPTIONS) konkretisiert. Natürlich verhalten sich Ressourcen unterschiedlich, aber sie haben einen gemeinsamen Kontrakt, der in der HTTP-Spezifikation definiert wird. Eine spezifische Ressource, zum Beispiel eine Kundenliste, kann von einem darauf spezifisch zugeschnittenen Client genauso genutzt werden wie ein mit einer anderen Technologie realisierter Dienst (Abb.1). Implementiert die Ressource das HTTP-Interface korrekt, kann sie jedoch auch von einem generischen Client benutzt werden – sei es ein Browser, ein Kommandozeilenwerkzeug wie curl oder wget oder ein externer Dienst wie Google oder Yahoo!.

Was genau legt die HTTP-Spezifikation als Semantik der einzelnen Methoden fest? Da die generische Schnittstelle auf alle Ressourcen anwendbar sein muss, ist sie naturgemäß allgemein gehalten. Sie definiert GET als eine lesende Operation, die "sicher" ist. Das heißt, dass ein Client durch ein HTTP GET keine Verpflichtung eingeht. Für GET ist außerdem ein sehr mächtiger Caching-Mechanismus spezifiziert, der eine feingranulare Kontrolle erlaubt. PUT legt eine neue Ressource unter einem bekannten Namen an bzw. aktualisiert sie dort. Ebenso wie DELETE und GET ist PUT idempotent: Weiß der Client nicht, ob die Operation erfolgreich war oder nicht, kann er die Operation gefahrlos wiederholen. Ein POST legt eine untergeordnete Ressource an und ist die einzige Operation, für die es keine Garantien gibt.

Die Herausforderung für den Entwickler einer REST-konformen Anwendung besteht vor allem darin, die auf andere Architekturen wie CORBA, RMI, DCOM oder auch Web Services zugeschnittenen Gewohnheiten abzulegen. Es wird nicht für jeden Service eine eigene Schnittstelle entworfen, mit ganz spezifischen Operationen und Datentypen. Stattdessen muss die applikationsspezifische Funktionalität auf die uniforme Schnittstelle abgebildet werden. Im Gegensatz dazu wird bei SOAP/WSDL – ähnlich wie bei CORBA, DCOM und anderen Vorgängern – für jede Applikation eine neue, eben applikationsspezifische Schnittstelle erfunden. Dementsprechend können auch nur solche Systeme diese Schnittstelle nutzen, die explizit dafür entwickelt wurden.

Beispiel: Serienbriefe

Sehen wir uns zur Verdeutlichung ein konkretes Beispiel an: den Entwurf einer Schnittstelle für einen Serienbriefservice, einen Dienst für den Versand eines einheitlichen, ggf. personalisierten Texts an eine Vielzahl von Empfängern. In einem klassischen Entwurf würden Sie vielleicht zunächst die dienstspezifische Schnittstelle entwerfen, mit Operationen wie Vorlage anlegen, Brief versenden, Methoden zur Verwaltung von Adressen usw. Bei näherer Betrachtung ist diese Schnittstelle jedoch gar nicht so spezifisch wie man zunächst glaubt: Viele der zentralen Objekte werden vom Dienst (oder dem System, das den Dienst anbietet – je nach Terminologievorliebe) verwaltet, müssen also dort angelegt, geändert, gelöscht und ausgelesen werden. Diese CRUD-Funktionalität ist recht leicht abzubilden. Bei der REST- Variante unseres Beispieldienstes würden wir dazu vielleicht URIs der in Listing 1 dargestellten Form definieren.

Wir haben damit zunächst eine Art Stammdatenverwaltung für die Serienbriefe erstellt, die allerdings nun aufgrund der generischen Schnittstelle nicht nur von einem spezifischen Client, sondern auch von einem allgemeingültigen wie z.B. dem Browser verwendet werden kann. Voraussetzung dafür ist, dass das Format, der Content Type, bekannt ist – kleinster gemeinsamer Nenner ist HTML oder XML, aber auch ganz spezifische Formate wie z.B. VCard, eine standardisierte XML-Instanz, RSS oder Atom können sinnvoll sein. Und da eine Ressource mehrere Repräsentationen haben kann, lassen sich diese sinnvoll kombinieren – ein Standardformat für den generischen, ein spezifisches für einen genau auf die Anwendung zugeschnittenen Client.

Darüber hinaus müssen wir nun alle Operationen auf eine der Standardoperationen abbilden, die für Ressourcen zur Verfügung stehen. Aus der Operation Brief versenden wird damit Versandauftrag anlegen. Dieser Auftrag hat nun eine eindeutige ID (URI) und kann als Link-Ziel dienen, sein Status kann abgefragt werden, auch eine Änderung ist möglich (wenn auch sicher nur so lange, wie er noch nicht ausgeführt wurde). Die eigentliche Briefproduktionsmaschinerie kann ihre Aufträge abfragen, indem sie sich per GET über die Liste der noch offenen Aufträge informiert und den jeweils nächsten anstehenden verarbeitet. Neu angelegte oder abgeschlossene Aufträge könnten gleichzeitig als Newsfeed zur Verfügung gestellt werden, sodass man sich mit einem Standardnewsreader über den aktuellen Status informieren kann.

Die zentralen Konzepte – oder, wenn Sie möchten, Objekte – unserer Anwendung haben nun einen eigenen, stabilen URI. Diese Eigenschaft machen wir uns zunutze, um die erweiterte Funktionalität umzusetzen: Das Anlegen eines neuen Versandauftrags könnte aus einem POST von Links auf die Adressen, an die versandt werden soll, sowie einer weiteren Verknüpfung zur Vorlage bestehen. Wird ein Brief an eine große Anzahl von Empfängern versandt, könnte stattdessen ein Link auf die Collection-Ressource, die die passende Menge zurückliefert, enthalten sein. Das Spannendste daran ist, dass die einzelnen Bestandteile der Anwendung ebenfalls nur über die uniforme Schnittstelle gekoppelt sind. Eine andere Adressverwaltung als die in unsere Lösung integrierte könnte einfach angebunden werden, wenn sie ebenfalls einzelne URIs für ihre Elemente und den gleichen Content-Typ unterstützt.

Noch Fragen?

Ist REST nun der nächste große Hype nach Web Services? In gewisser Weise ist die Antwort ein klares "Jein". Auf der einen Seite stammt die REST-Dissertation aus dem Jahr 2000, und sie beschreibt die Prinzipien, die dem Design des WWW schon vorher zugrunde lagen. Mit den Worten von Roy Fielding: "SOAP was known to be a bad idea in 1999, but in spite of our comments to this effect, the industry insisted on proving that for themselves". REST gab es also schon lange vor Web- Services. Auf der anderen Seite ist unbestreitbar, dass aus einem Thema, das vor zwei oder drei Jahren noch relativ exotisch war, mittlerweile ein Aufmerksamkeitsmagnet geworden ist. Unabhängig stellt man sich nach einer ersten Beschäftigung mit dem Thema zunächst einige Fragen – irgendwie kann das Ganze nicht funktionieren! Oder doch? Die häufigsten Zweifel möchte ich im Folgenden ansprechen.

REST = CRUD?

Weil REST die Menge von Operationen auf einige wenige (GET, PUT, POST, DELETE) beschränkt, könnte man annehmen, mit REST könne man bestenfalls eine simple Datenverwaltung aufbauen, nicht jedoch fortgeschrittene Anwendungsfälle. Aber REST ist nicht das Gleiche wie CRUD: Ob es sich um eine Web-Service-Operation mit dem Namen submitOrder oder ein POST auf /orders handelt: in beiden Fällen kann und sollte dahinter Geschäftslogik ablaufen und nicht nur ein simples Einfügen eines Datensatzes. Viele Operationen bewirken als Haupteffekt die Änderung oder Neuanlage eines Geschäftsobjekts; für diese Fälle ist die Abbildung auf das generische REST-Interface sehr einfach. Für die zusätzlichen Anwendungsfälle besteht der Trick darin, Aktionen auf eigene Ressourcen abzubilden: aus Verben werden Substantive. Statt einen Status zu ändern, legt man eine neue Statusänderung an, aus cancel subscription wird create SubscriptionCancellation usw. Einige Beispiele für eine solche Abbildung sind in Listing 2 dargestellt. Es erfordert zwar eine gewisse Übung; hat man sich jedoch einmal daran gewöhnt, denkt man ganz automatisch in Ressourcen. Darüber hinaus ergeben sich diverseVorteile – individuelle Aktionen (bzw. ihre Ergebnisse) sind historisierbar, man kann sie verlinken, sie wieder zurücknehmen und die Ergebnisse in unterschiedlichen Formaten zur Verfügung stellen.

Teil 1   Teil 2   Teil 3   

Anzeige

Kommentare

Gravatar Mr. Checker 04.11.2009
um 11:38 Uhr
Test #zitieren
Gravatar hp 18.02.2010
um 14:57 Uhr
sehr guter Artikel! komplizierte Materie leicht verständlich erklärt :) #zitieren
Gravatar Quirin 01.03.2010
um 12:52 Uhr
Danke für den leicht verständlichen Artikel.

Mir fehlt jedoch der unabdingbare Faktor REST-Sicherheit der mit WSS bei Webservices umfassend erschlagen wird.
#zitieren
Gravatar Ellen 13.09.2010
um 23:57 Uhr
supppppppppppppppi danke #zitieren
Gravatar Volker 25.01.2011
um 21:01 Uhr
Wirklich schöne Seite die ihr da habt.............
Bin schon ein paar mal auf eurer Seite gewesen und jetzt hab
ich mir gedacht, ich schreib euch mal was nettes ins Gästebuch.
Also echt toll was ihr hier gemacht habt.
Macht weiter so............ :)
Bis bald
#zitieren
Gravatar cforce 28.02.2012
um 07:36 Uhr
Ich finden das Beispiel performTrafficCalculation(Data) sehr interessant aber zu wenig erklärt. Geh ich richtig in der Annahme das dort über zwei Requetsts Post (Parameter) and Get Result die Soap Methodenähnliche Schnittstellenabbildung nachgeahmt wird? Da Rest per se zustandlos ist frage ich mich wie genau dafür gesorgt wird das eine neue Ressource (calculcations/4711) temporär (bis zum get request verfügbar ist um das Ergebnis abzuholen? IN usnerem Fall haben wir einen dynmaische Liste von Parametern welche so zu sagen erst beim request die Daten in einer Ressource spezifizieren. Danke für das Feedback #zitieren
Gravatar Macias De La Rosa Jesus 27.03.2012
um 12:02 Uhr
Sehr guter Beitrag. Endlich ein sachlich informativer Beitrag zu diesem Thema ( leicht und einfach zu verstehen) #zitieren
Gravatar Perfetti 28.03.2012
um 08:48 Uhr
Bei uns gibt es Überlegungen eine nur noch schwer zu pflegende PHP-Anwendung dergestalt umzubauen, dass alle Datenbankzugriffe über REST Web Service vorgenommen werden. In einem weiteren Schritt soll dann die Datenbankstruktur und Zugriffe (SELECT, INSERT, UPDATE) optimieren werden - auch hier scheint manches im Argen zu liegen - und in einem letzten Schritt soll dann die PHP-Anwendung selbst überarbeitet werden.

Ist das ein sinnvoller Ansatz? Hat jemand Erfahrungswerte - positiv oder auch negativ - mit so einer Vorgehensweise? Wo lauern die größten Fallen?
#zitieren

Anzeige

zurück zum Seitenanfang