Representational State Transfer - exxcellent.de · (sehr viele APIs lassen sich auf diese simple...
Transcript of Representational State Transfer - exxcellent.de · (sehr viele APIs lassen sich auf diese simple...
REST Representational State Transfer
Gastvortrag
31.05.2016
REST 3 |
eXXcellent - Zahlen und Fakten
Ulm
• Gegründet 2001 durch
Führungskräfte der
ehemaligen tiscon AG
• 60 Mitarbeiter
• 6 Mio € Umsatz
München / Stuttgart
• Gegründet April 2012
durch Führungskräfte der
ehemaligen sd&m AG
• Aktuell 40 Mitarbeiter
• Umsatz 4,1 Mio € Mitglied im
Nach ISO 9001:2000 und ISO 14001:2005 zertifiziert
REST in Kürze
l REST ist kein Protokoll
l REST ist auch kein Standard
l REST ist ein Architekturstil beschrieben in der Dissertation von Roy Fielding
– Architectural Styles and the Design of Network-based Software Architectures
– https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
l REST ist eigentlich ganz einfach
l vieles, was sich RESTful nennt hat mit der von Roy beschriebenen Idee nichts zu tun
l Naiv von außen betrachtet:
– SOAP: Schwerfällig, kompliziert, Old-School
– REST: Leichtgewichtig, einfach, hipp
REST 4 |
REST in Kürze
REST richtig implementiert ist:
l cachefähig
l selbsterklärend
l zustandslos
l skalierbar
l fehlertolerant
l schwach gekoppelt
REST 5 |
REST in Kürze
REST 6 |
Copyright by Geek&Poke
http://geekandpoke.typepad.com/geekandpoke/2009/11/service-calling-made-easy-part-1.html
Richardson maturity model (RMM)
REST 7 |
Your API looks
like Level 1
Copyright by Martin Fowler:
http://martinfowler.com/articles/richardsonMaturityModel.html
Richardson maturity model (RMM)
l Level 0
– Plain old XML
– senden von Nachrichten
– ein Endpunkt, Logik nur im Content der Nachrichten abgebildet
– HTTP ist reines Transportmedium
– Beispiel SOAP
l Level 1
– mehrere Endpoints
– Ansteuerung unterschiedlicher Ressourcen
– Logik weiterhin in den Nachrichten gekapselt
– nur ein HTTP Verb wird verwendet (meist POST oder GET)
Level 0 und Level 1 verwenden HTTP als Transportmedium
REST 8 |
Richardson maturity model (RMM)
l Level 2
– HTTP Verbs finden Verwendung: GET/PUT/POST/DELETE/…
– unterschiedliche Endpoints für unterschiedliche Ressourcen
– viele sogenannte RESTful APIs bewegen sich auf diesem Level
l Level 3
– wirklich RESTful
– der volle Protokollumfang von HTTP wird verwendet
– HEATEOAS (Hypertext As The Engine Of Application State)
REST 9 |
REST 10 |
Become a proud REST API developer
I can master
level 3
Nouns are good, verbs are bad
Never ever!
http://api/accounts/1/transfer/500.00/to/2
http://api/products/74/getDetails
http://api/products/getSortedList
http://api/products/getList
http://api/products/new
http://api/products/23/delete
REST 11 |
Nouns are good, verbs are bad
Richtig ist:
l GET: /products/4711 – Liefert die Details des Produktes 4711
l POST: /products – Legt ein neues Produkt an (Daten im Body)
l DELETE: /baskets/42/56 – Löscht aus dem Warenkorb 42 das Produkt 56
Falsch wäre:
l GET: /api/getProduct?id=4711
l POST: /api/createProduct
l POST: /api/deleteItem?basket=42&id=56
REST 12 |
Nouns are good, verbs are bad
Richtig ist:
l GET: /products/4711 – Liefert die Details des Produktes 4711
l POST: /products – Legt ein neues Produkt an (Daten im Body)
l DELETE: /baskets/42/56 – Löscht aus dem Warenkorb 42 das Produkt 56
REST 13 |
Ressource POST GET PUT PATCH DELETE
/products Neues
Produkt
anlegen
Liefert eine
Liste aller
Produkte
- - Löscht alle
vorhandenen
Produkte
/products/42 - Liefert die
Details zum
Produkt 42
(komplettes)
Update von
Produkt 42
(partielles)
Update von
Produkt 42
Löschen von
Produkt 42
Allgemeines Schema (sehr viele APIs lassen sich auf diese simple Struktur zurückführen - einfaches CRUD)
Idempotent – mehrfache Ausführung ergibt gleiches Ergebnis
Nouns are good, verbs are bad
Falls darüber hinaus wirklich Aktionen notwendig sind:
l GET: /products/ - Liefert alle verfügbaren Produkte
l GET: /products?order=price – Liefert alle verfügbaren Produkte nach Preis sortiert
l GET: /products?order=price &limit=5 – Liefert alle verfügbaren Produkte nach Preis
sortiert, aber nur die ersten 5
Falsch wäre
l GET: /products/ordered
l GET: /products/ordered/limit/5
REST 14 |
REST 16 |
HATEOAS
Hypermedia
as
the
engine
of
application
state
Dude,
what‘s
that?
HATEOAS - Hypermedia
l Verweise und Verlinkungen
l Es können unterschiedliche Ressourcen adressiert werden
l Intern und extern
l Jede vernünftige Webseite lebt nach diesem Konzept
l Davon lebt das Web
REST 17 |
HATEOAS - Engine
l Wörtlich: Maschine
l In diesem Kontext gemeint: Zustandsautomat
l Zustandsübergänge natürlich mittels
(Hypermedia) Links
REST 18 |
Start
Kasse Warenkorb
Login
Artikel hinzufügen bezahlen
HATEOAS - Application
l Gemeint sind die einzelnen Ressourcen (Ressource = Applikation)
l Der Zustand einer Ressource soll rein mit den Mitteln von HTTP abgebildet werden
l Der Server kennt den Zustand einer Ressource (und somit der Applikation) nicht
-> Der Server ist Zustandslos (stateless)
REST 19 |
HATEOAS - State
l Zustand
l Verbindet Engine und Application
l Mit anderen Worten: Eine Ressource (Application) mit den dazu passenden
Informationen aus dem Zustandsautomaten (Engine) wird als State bezeichnet
REST 20 |
HATEOAS – Links in Ressourcen
AtomPub link gibt einen guten
Anhaltspunkt
Wichtig sind:
l href – das eigentliche Ziel
l rel – eine Beschreibung des Übergangs
Optional:
l type – HTTP content type
l method – HTTP Methode
REST 21 |
GET: /products (Liefert die Liste der Produkte)
{
„products": [
{
"name": "iMac",
"price": 976,
"link": {
"href": "products/17",
"rel": "details"
}
},
{
"name": "Dell XPS",
"price": 754,
"link": {
"href": "products/18",
"rel": "details"
}
}
]
}
HTTP Status Codes
REST 22 |
404 kennt jeder
HTTP Status Codes
l Um (maschinell) sinnvoll mit einer REST API zu arbeiten ist mehr als
– 200 :: OK
– 404 :: Not found
– 500 :: Internal Server Error
notwendig
l Statuscode sollen dem Aufrufer wirklich etwas über den Status des Aufrufes sagen
REST 23 |
HTTP Status Codes
Code Beschreibung Details
Erfolgreich
200 OK REST call erfolgreich
201 Created Ressource wurde angelegt
204 No content Request war erfolgreich, aber es lässt sich
kein sinnvoller Wert im Body zurückgeben.
z.B. für ein DELETE einer Ressource
Umleitungen
301 Moved
permanently
z.B. bei API Änderungen: die an sich
bekannte Ressource befindet sich nun an
einem anderen Ort
304 Not modified Antwort auf einen „conditional GET“ falls
sich die angeforderte Ressource nicht
verändert hat
REST 24 |
HTTP Status Codes
Code Beschreibung Details
Client Fehler
400 Bad Request Der Request wurde falsch gestellt, z.B. String
values in query Parametern, an denen
Integer erwartet wird
401 Not Authorized Client ist nicht authentifiziert
403 Forbidden Der Request an sich ist valide, aber der
Client besitzt nicht die notwendigen Rechte
404 Not found Die gewünschte Ressource wurde nicht
gefunden
Server-Fehler
500 Internal Server
Error
Es ging wirklich im Server etwas
(unerwartetes) schief
501 Not
implemented
Die gewünschte Funktionalität (z.B. DELETE)
ist bisher nicht umgesetzt
REST 25 |
HTTP Status Codes
REST 26 |
l HTTP Errors können im Body Details übermitteln
l z.B.: GET: http://www.fancyApp.de/bookings?createdOn=01052015
l Nur ein Beispiel, aber
– errorId: Damit lassen sich die HTTP Code (welche von der gesamten Kette von
Sender zu Empfänger verstanden werden) weiter klassifizieren. So kann der Client
sehr einfach mittels eines internen Mappings auf den Fehler reagieren
– detailMessage: Freundliche Server liefern dem Client eine sprechende
Fehlermeldung, die dort entweder im LOG oder sogar direkt dem Endbenutzer
angezeigt werden kann.
HTTP CODE: 400
{
"errorId": 42,
"detailMessage": "Wrong date Format for parameter 'createdOn'. Valid format: yyyy-MM-DD"
}
… do you know:
418
REST 28 |
By the way…
Hyper Text Coffee Pot Control Protocol
https://tools.ietf.org/html/rfc2324
Austauschformate
REST 29 |
Austauschformate - XML
l XML war lange das einzig akzeptierte (maschinenlesbare) Austauschformat
l Sonstige Ascii-basierten Formate waren/sind meist proprietär
l Sehr gute Toolunterstützung
l Praktisch von allen Programmiersprachen unterstützt
l Auch für Menschen (theoretisch) lesbar
l Man kann es „ausdrucken“ und archivieren
l Klar definiert durch XML Schema
l Aber…:
– Relativ großer Overhead
– Und das mit der Lesbarkeit ist so eine Sachen für sich…
REST 30 |
Austauschformate - JSON
l Strukturiert, aber nicht so mächtig wie XML
l Weniger Struktur-Overhead
l Gute Toolunterstützung
l Praktisch von allen Programmiersprachen unterstützt
l Auch für Menschen lesbar
l Auch JSON kann man „ausdrucken“ und archivieren
l JSON-Schema bietet ähnliche Möglichkeiten wie XML-Schema (Validierung,
Dokumentation, …)
l Im JavaScript Bereich: JSON-Objekte sind faktisch JS Objekte
– JSON = JavaScript Object Notation
REST 31 |
JSON-Schema
l Nicht ganz so mächtig wie XML Schema
l Verfolgt aber ähnlichen Ansatz:
– XML Schema wird in XML beschrieben / JSON-Schema wird in JSON beschrieben
l Aber noch nicht so präsent in der Toolchain
l Standard liegt als Draft vor (Version 4)
– http://json-schema.org/documentation.html
l Validatoren unter anderem Verfügbar für:
– JavaScript
– Java
– Ruby
– PHP
– .Net
– Objective-C
– …
REST 32 |
JSON-Schema
REST 33 |
{
"$schema": "http://json-schema.org/schema#",
"name": "Product",
"type": "object",
"required": ["name", "price"],
"properties": {
"name": {
"type": "string",
"description": "Name of the product"
},
"price": {
"type": "number",
"minimum": 0
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
{
"name": “Laptop",
"price": 123,
"tags": [
“SSD",
“core i7"
]
}
https://en.wikipedia.org/wiki/JSON#Schema_and_Metadata
Content negotiation
l HTTP bietet einen definierten Weg, wie ich die Repräsentation einer Ressource
mitgeteilt werden kann
Falsch
l GET: product/42/json oder auch: GET: product/42?format=json
l GET: product/42/xml oder auch: GET: product/42?format=xml
Richtig
l GET: product/42
l Passender HTTP Accept/Content Type Header
REST 34 |
Accept: application/vnd.fancyApp.product+xml
Content-type: application/vnd.fancyApp.product+xml
Accept: application/vnd.fancyApp.product+json
Content-type: application/vnd.fancyApp.product+json
request
response
request
response
API Versionierung
l Anforderungen können (und werden!) sich ändern
l Die Evolution von Software ist oft sehr dynamisch
– Eine Fußgängerbrücke wird nie zu einer Eisenbahnbrücke umgebaut
werden
– Eine Verwaltungssoftware für Turnschuhe kann aber durchaus auch
Eisenbahnschwellen verwalten…
l Dies sollte auch beim Design einer REST API betrachtet werden
l Einfache Client/Server Konstrukte, bei denen es eine 1:1 Abbildung +
gemeinsames Deployment gibt gestalten sich einfach -> Hier sind keine
wirklich versionierten APIs notwendig
l Öffentliche APIs mit n (teilweise unbekannten) Clients müssen zwingend
versioniert werden
REST 35 |
API
Client
Client
Client
API Client
API Versionierung – Exkurs: semver
l „semver“ – Semantiv Versioning Pattern:
– Major.Minor.Bugfix
– 1.0.0 vs. 1.0.7 vs. 1.3.0 vs. 2.2.0
l Etabliertes und einheitliches Verständnis in der Branche
l Bugfix
– Keine API Breaks, Änderungen am Verhalten oder zusätzliche Funktionalität
– Lediglich Fehlverhalten der Anwendung wird bereinigt
l Minor
– Keine API Breaks
– Rückwärtskompatible Erweiterung der Funktionalität
l Major
– API Breaks
– Geändertes Verhalten der bisherigen Logik
REST 36 |
API Versionierung - REST
l Für REST API kursieren mehrere Ansätze zur Versionierung
l Teilweise arten Diskussionen darüber zu Religionskriegen aus
– Stackoverflow: http://stackoverflow.com/questions/389169/best-
practices-for-api-versioning
– Über 170.000 Views
– „closed as primarily opinion-based“
l Die offensichtlichen Ansätze sind nicht REST konform
l Es muss jedoch auch die „Intelligenz“ der Clients betrachtet werden
– Ein API die von tausenden von verschiedenen Clients bedient wird
sollte ein sehr einfaches Konzept verfolgen – Clientprogrammierer
könnten sonst überfordert sein
– Eine Business-API die von wenigen Clients bedient wird, die zudem
noch hohe Anforderungen stellen sollte auch ein sehr klares
Versionskonzept verfolgen. Hier sollte Komplexität keine zu
schwergewichtiges Argument sein
REST 37 |
API Versionierung – URL basiert
l http://fancySite.de/api/v3.1/products/42
l http://fancySite.de/api/v2/products/42
l Wird oft bei stark frequentierten öffentlichen Service APIs verwendet
– Twitter, Facebook Graph API, …
l Leicht verständlich und einfach anzusprechen
l Hat jedoch nichts mit REST zu tun!
– Für jede neue Version ändern Ressourcen ihre Adresse
– HATEOAS: URIs müssen stabil sein
– Es wird im obigen Beispiel die selbe Ressource betrachtet (Produkt
mit der Nummer 42), allerdings mit unterschiedlichen Ressourcen.
Eigentlich handelt es sich aber lediglich um eine (potentiell)
andere/neuere Repräsentation von Produkt 42
REST 38 |
API Versionierung – URL basiert die Zweite
l Wenn schon, denn schon:
l http://fancySite.de/api/products/42 (zeigt auf 3.1)
l http://fancySite.de/api/v3.1/products/42
l http://fancySite.de/api/v2/products/42
l Die eigentliche REST-API zeigt immer auf die aktuelle Version
l Zusätzlich ist jede Version (auch die aktuelle) über eine Versionsbezogene
Route erreichbar
l Clients, die sich an die aktuelle Releasezyklen des Servers halten, können
somit mit festbleibenden Routen arbeiten
l Clients ,die abweichende Versionen nutzen wollen, können die
Versionsbezogenen Routen verwenden
REST 39 |
API Versionierung – jetzt richtig
Zur Erinnerung:
l HTTP content negotiation: Mehrere Ressource-Repräsentationen unter
einer URL
l Damit lässt sich auch explizit eine Version für eine Ressource setzen
REST 40 |
API Versionierung – jetzt richtig
l Versionierung rein über von HTTP bereitgestellte Mittel
l HATEOAS konform
l -> stabile URLs
l Für hochfrequentierte und von „Laien“ genutzte APIs jedoch oft leider
ungeeignet, da mit einer gewissen Grundkomplexität verbunden
l Für Business-APIs jedoch essentiell
– Komplexität ist beherrschbar (wenn man das Grundkonzept verstanden hat)
– Content negotiation findet dort so oder so mit der Zeit Verwendung
– Benefit durch eine wirkliche REST konforme API zahlt sich schnell aus
REST 41 |
API Versionierung – jetzt richtig
l Anfrage für Version 3
REST 42 |
GET /products/123
Accept: application/vnd.company.fancyapp.product-v3+json
request
200 OK
Content-Type: application/vnd.company.fancyapp.product-v3+json
response
l Version 2
l Alternativ kann als Shortcut für die aktuelle Version auch ein call ohne
Versionsbezug erlaubt werden
GET /products/123
Accept: application/vnd.company.fancyapp.product-v2+json request
GET /products/123
Accept: application/vnd.company.fancyapp.product+json
request
200 OK
Content-Type: application/vnd.company.fancyapp.product-v3+json
response
Dokumentation
l Für REST Services gilt ähnlich wie für Code:
„Die beste Dokumentation ist diejenige, die gar nicht
benötigt wird“
l REST APIs können zu einem großen Teil selbstdokumentierend sein:
– Nutzung von durch HTTP klar definierten Bestandteilen
– HATEOAS mit deklarierten Zustandsübergangen in den Ressourcen
– REST CRUD best practice mit:
l GET / PUT / PATCH / POST / DELETE
l /foos -> Liste
l /foos/:id -> einzelnes Objekt
REST 43 |
Dokumentation
Ohne Dokumentation geht es aber meist doch nicht – hier gilt:
l Übergeordnete Konzepte zentral beschreiben
l Jeder Service sollte jedoch für sich allein verständlich sein, ggfs. Verweis auf die
grundlegenden Konzepte
– größere REST APIs bestehen oft aus mehr als 100 Services
– einzelne Clients / Entwickler sind aber oft nur an kleinen Teilen daran interessiert
l Mögliche HTTP Status Codes (auch Fehler) beschreiben
l Beispiel-Calls für jeden Service bereitstellen
– möglichst direkt ausführbar mittels Tools wie: curl oder Postman
l Beispiel-Antworten zu jedem Call bereitstellen
l Um die Beschreibung und den Code in Sync zu halten kann die Dokumentation auch
zu großen Teilen generiert werden
REST 44 |
Tooling rund um REST
l Testen
– curl (Kommandozeilenbasiert)
– httpie (das bessere curl??)
– Postman (Chrome Plugin)
– RESTClient (FireFox Plugin – kann Postman jedoch nicht das Wasser reichen)
l (automatisierte) Stress- und Last- Tests
– SoapUI (kann auch REST)
– Apache JMeter
– Apache AB – Apache benchmarking tool
– gatling.io (Interessanter Stack: Scala / Akka / Netty)
l Dokumentation
– swagger.io
– apiblueprint.org (Markdownbasiert)
– wadl (Web Application Description Language – eher formell gehalten)
REST 45 |
REST in der Praxis
Eines der aktuellen Projekte bei eXXcellent
l REST basiertes Datenbackend
l CRUD + Constraints
l Versionierte API
l HATEOAS
l Suchanfragen/Einschränkungen in REST-Calls nach fast allen Attributen der
DomainObjekten
l Berechtigungs- und Sichtbarkeitskonzept auf einzelnen Entitäten möglich
l Technologiestack
– node.js
– restify Framework
– MongoDB
– gatling.io für Lasttests
– Json-Schema Validierung
REST 46 |
REST in der Praxis
Learnings aus dem Projekt + best practice
l Sei locker bei Anfragen, aber streng bei Antworten
l Dokumentiere jeden Service so, dass er für sich alleine verständlich ist
l Beispiele, Beispiele und nochmals Beispiele in der Doku
l HATEOAS macht wirklich Sinn!
l Durchgängige Konzepte etablieren und beibehalten:
– wer einen Service verstanden hat, wird auch die anderen bedienen können
– dem Konzept die Treue halten: Lieber Funktionalität anbieten, die fachlich nicht
benötigt wird (aber auch nicht falsch ist), als Ausnahmen zu bilden
l TDD bzw. Unit-Testing
– REST-APIs sind reine Logik -> über 90% Testabdeckung sind hier wirklich
realistisch!
REST 47 |
REST in der Praxis
Learnings aus dem Projekt + best practice
l Log‘s in einem asyncronen Server sind nur lesbar, wenn ein (Kontext-)Identifier mit
ausgegeben wird
Beispiel:
REST 48 |
2015-06-15T18:28 - info: 65a6d2055fbf GET /foo/55101c
2015-06-15T18:28 - info: 75a5d2a55fbb GET /foo/56100c
2015-06-15T18:28 - debug: 65a6d2055fbf Authentication failed
2015-06-15T18:28 - debug: 75a5d2a55fbb Authentication successful
2015-06-15T18:28 - info: 65a6d2055fbf Responding with 401
2015-06-15T18:28 - info: 75a5d2a55fbb Responding with 200
2015-06-15T18:28 - info: GET /foo/55101c
2015-06-15T18:28 - info: GET /foo/56100c
2015-06-15T18:28 - debug: Authentication failed
2015-06-15T18:28 - debug: Authentication successful
2015-06-15T18:28 - info: Responding with 401
2015-06-15T18:28 - info: Responding with 200
REST in der Praxis
Learnings aus dem Projekt + best practice
l REST APIs lassen sich wirklich einfach skalieren
Erprobtest Szenario aus dem Projekt:
l 5 node.js Instanzen
l 3 MongoDB Instanzen
l Mit jeweils 3 Shards
Das Szenario lief ohne
Anpassungen am Code durch
Aufeinanderfolgende Calls von
Client X wurden wirklich durch
verschiedene Node-Instanzen und
verschiedene MongoDB Instanzen
verarbeitet
-> Keinen Zustand zu haben ist schön
REST 49 |
Client Client
Client Client
Node.js
Load balancer
Node.js Node.js Node.js Node.js
MongoDB
Shard
Shard
Shard
MongoDB
Shard
Shard
Shard
MongoDB
Shard
Shard
Shard
Client Client
Client Client
Further Reading
l http://martinfowler.com/articles/richardsonMaturityModel.html
l http://semver.org/
l http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
l http://restcookbook.com/
l http://restinpractice.com/book/
– O‘REILLY
– ISBN: 978-0-596-80582-1
REST 50 |
REST 51 |
Vielen Dank
Fragen...?
eXXcellent solutions GmbH
Beim Alten Fritz 2
89075 Ulm
http://www.exxcellent.de
Bildquellen:
http://www.sxc.hu/
http://www.freeimages.com/