pragmatic rest aka praxisnahes schnittstellendesign
TRANSCRIPT
#WISSENTEILEN
What would MacGywer do?
Pragmatic REST
Lars Röwekamp | open knowledge
@mobileLarson@_openKnowledge
#wissenteilen
#WISSENTEILEN
RESTfuleverywhere
#WISSENTEILEN
SOAPDemoPOST /InStock HTTP/1.1
Host: www.demo.orgContent-Type: application/soap+xml; Content-Length: 348
<?xml version="1.0" encoding="utf-8"?><soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope"><soap:Header></soap:Header><soap:Body>
<m:GetStockPrice xmlns:m="http://www.demo.org/stock"><m:StockName>IBM</m:StockName>
</m:GetStockPrice></soap:Body>
</soap:Envelope>
#WISSENTEILEN
XML-RPCDemoPOST /InStock HTTP/1.1
Host: www.demo.orgContent-Type: application/xml; Content-Length: 245
<?xml version="1.0" encoding="utf-8"?><getStockPriceRequest
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation=“storckItemRequest.xsd"><stockName>IBM</stockName>
</getStockPriceRequest>
#WISSENTEILEN
GET /stocks/ibm HTTP/1.1Host: www.demo.orgContent-Length: 0
RESTDemo
#WISSENTEILEN
Warum REST?
Keep it stupid simple a.k.a. KISS
• REpresentational State Transfer
• Identifikation von Ressourcen durch URL• Manipulation von Ressourcen durch Representation• Selbstbeschreibende Messages• Hypermedia
/customers/123
JSON/XML
GET, POST, PUT, DELETEMedia Types, CachabilityReferences
{?}
#WISSENTEILEN
Warum PRAGMATIC REST?
„Yo man! But it is
not RESTful, if ...“
{ }…{…}{?}
(RESTafarian, by Mike Schinkel)
#WISSENTEILEN
„But is thispragmatic?“
„Pragmatic? Are you
kidding? ItsCORRECT!“
Warum PRAGMATIC REST?…{?}
#WISSENTEILEN
„Das* API ist das UI des Entwicklers.“
(*wer möchte darf auch “die API“ sagen)
#WISSENTEILEN
„So what? Itspragmatic andworks for me
and myconsumers!“
Warum PRAGMATIC REST?{?}
#WISSENTEILEN
RESTbucks... ordering Coffee the RESTful way
#WISSENTEILEN
„Order 123 for‚Larissa‘.“
„And here‘s thereceipt.“
„Coffee, latte, large, to-go, semi, double shot, please.“
„Here‘s 5$.“
„What‘s thestatus of ‚123‘?“„Still prepering.“
„Now its ready.“
REST by Example
#WISSENTEILEN
// order coffeePOST /orders{ ... initial order data ... }
// check order statusGET /orders/1234
// change orderPUT /orders/1234{ ... changes ... }
// cancel orderDELETE /orders/1234
RESTBucks„crud“
given id?
filter, query, sorting?
PUT? Or PATCH?
Security?
Versionioning?
Error Handling?
Content Type?
#WISSENTEILEN
REST... the simple Stuff
#WISSENTEILEN
• „We only need two URLs“ • „Verbs are bad, nouns are good“• „Plurals are even better“
• „The web is your friend“
• „There is always a root (for associations)“• „There is always a parameter (for complex variations)“• „There is always a method (for an operation)“
Golden Rules of REST
#WISSENTEILEN
// Retrieve single order with id 1234GET /orders/1234
// Retrieve all ingredients of order 1234GET /orders/1234/ingredients
// Retrieve ingriedient 789 (milk) of order 1234?GET /orders/1234/ingredients/789
// Or even better: What kind of milk is in order 1234?GET /orders/1234/ingredients/milk
REST„root“
#WISSENTEILEN
// Path parameter for identifierGET /orders/1234
// Query parameter for queriesGET /orders/?status=ready
// Header parameter for platformGET /orders/1234Accept-Language: de-DE
REST„param“
#WISSENTEILEN
// „Create order“, isn‘t it?POST /orders
// Is this allowed? Guess not. Or ...? POST /orders/1234
// „Change order“. I‘am sure!PUT /orders/1234
// „Change order“, too? Isn‘t it?PATCH /orders/1234
REST„method“
#WISSENTEILEN
POST vs. PUT vs. PATCH
POSTerzeugt Child Resource an Server-definierter URI
PUT erzeugt/ändert Child Resource an Client-definierter URI
PATCHändert Teile einer Child Resource an Client-definierter URI
#WISSENTEILEN
// Creates order. Returns ID 1234POST /orders{ ... payload for 1234 ... }
// Hmmm, updates order 1234? Creates new order? POST /orders{ ... payload for 1234 ... }
REST„method“
#WISSENTEILEN
// Changes order with ID 1234PUT /orders/1234{ ... changes for 1234 ... }
// Hmmm, will be irgnored? PUT /orders/1234{ ... changes for 1234, e.g. set amount of milk ... }
// Or additional changes? PUT /orders/1234{ ... changes for 1234, e.g. add more milk ... }
REST„method“
#WISSENTEILEN
// Changes order with ID 1234PUT /orders/1234{ ... changes for 1234 ... }
// Same as PUT? Mayby not! PATCH /orders/1234{ ... changes for 1234 ... }
// Same as PUT? Is this what i expect?GET /orders/1234?milk=soja orGET /orders/1234/addSojaMilk
REST„method“
#WISSENTEILEN
SAFE / IDEMPOTENT Methods
SAFE*keine Änderung an der Ressource
IDEMPOTENT**einmalige Änderung an der Ressource-Representationmehrfache Wiederholung führt immer zum selben Ergebnis
* GET, HEAD, OPTIONS** GET, HEAD, OPTIONS, PUT, DELETE
#WISSENTEILEN
REST... Filter, Sorting & Pagination
#WISSENTEILEN
Filter, Sorting, Pagination,
Was ist eigentlich mit ...
• komplex(er)en Anfragen?• eingeschränkten Rückgabeobjekten?• (alternativen) Sortierungen?• alternativen Rückgabeformat?
Und wie sieht es mit „allgemeiner“ Suche aus?
#WISSENTEILEN
// FILTERING: // List of paid orders (2015-12-20)
// Common StyleGET /orders?date=20151220&status=payed HTTP 1.1
REST„filter“
#WISSENTEILEN
// FILTERING: // Details of order 3 (product, date, ...)
// Facebook StyleGET /orders/3?fields=product,date,status HTTP/1.1
GET /orders/3?fields=item.product,date,status HTTP/1.1
// LinkedIn StyleGET /orders/3:(product, date, status) HTTP/1.1
REST„filter“
#WISSENTEILEN
// FILTERING: // Details of order 3
// without date, statusGET /orders/3?exclude=date,status HTTP/1.1
// predefined payload (compact = product, date, status)GET /orders/3?style=compact HTTP/1.1
REST„filter“
What is compact?
#WISSENTEILEN
// FILTERING: // Details of order 3
// using PREFER HEADER for response payload definitionGET /orders/3 HTTP/1.1Content-Type: application/jsonPrefer: return=compact-format
HTTP 1.1 200 OKContent-Type: application/json; charset=utf-8Preference-Applied: return=compact-format
REST„filter“
#WISSENTEILEN
// SORTING: // orders sorted (date ↓ /item ↑)
// SQL alike styleGET /orders?sort=date+DESC,item+ASC HTTP/1.1
// Sort and asc/desc combination, ascending as defaultGET /orders?sort=date,item&desc=date HTTP/1.1
// use prefix „-“ for descending, ascending as defaultGET /orders?sort=-date,item HTTP/1.1
REST„sorting“
#WISSENTEILEN
// FILTERING & SORTING: // orders of „today“ sorted by ...
// long versionGET /orders?status=open
&date_from=20170510&date_to=20170510&fields=product,status,time&sort=-time,product
// short and readable versionGET /orders/open_orders_of_todayGET /open_orders_of_today
REST„filter&sort“
#WISSENTEILEN
// Pagination: // return page 4 of orders
// Is page a query parameter?GET /orders?page=4 HTTP/1.1
// Or is page a „virtual“ resource?GET /orders/pages/4 HTTP/1.1
REST„pagination“
„4“?
PREV? NEXT? FIRST? LAST?
#WISSENTEILEN
// Pagination: // return page 4 of orders
// get “page 4“ and info about PREV/NEXT GET /orders?offset=20&limit=5 HTTP/1.1
// Response with success code and link header for// navigation purposeHTTP/1.1. 200 OKLink: <.../orders?offset=0&limit=5>; rel=„first“
<.../orders?offset=5&limit=5>; rel=„prev“, <.../orders?offset=15&limit=5>; rel=„next“,<.../orders?offset=40&limit=2>; rel=„last“
REST„pagination“
#WISSENTEILEN
// Pagination: // return page 4 of orders
// get “page 4“ and info about PREV/NEXT GET /orders?page=4&limit=5 HTTP/1.1
// Response with success code and link header for// navigation purposeHTTP/1.1. 200 OKLink: <.../orders?page=1&limit=5>; rel=„first“
<.../orders?page=3&limit=5>; rel=„prev“, <.../orders?page=5&limit=5>; rel=„next“,<.../orders?page=8&limit=2>; rel=„last“
REST„pagination“
#WISSENTEILEN
// FULL TEXT SEARCH: // Fulltext search for coffee
// Global style via virtual resourceGET /searches?q=coffee HTTP/1.1
// Scoped styleGET /orders/searches?q=coffee HTTP/1.1GET /orders?q=coffee HTTP/1.1
REST„search“
#WISSENTEILEN
// ADVANCED SEARCH: // Coffee WITH milk for 2€
// Query for ... GET /orders?type=coffee&ingredient=milk&price=2
REST„search“
BTW: AND or OR orAND/OR?
#WISSENTEILEN
// ADVANCED SEARCH: // Coffee WITH milk for LESS THAN 2€
// Query for ... GET /orders?query=type=coffee+ingredient=milk+price<=2
REST„search“
Build your own„Query Language“?
#WISSENTEILEN
Filter, Sorting, Pagination
Resource Query Language (RQL*)
• Object-Style Query Language• FIQL Superset (erweiterbar)
• Spezifikation & JS Parser (Client & Server)• JS Array, SQL, MongoDB, Elastic Search• Java Parser + JPA Criteria Builder
(* https://github.com/persvr/rql)
#WISSENTEILEN
// ADVANCED SEARCH: // Coffee WITH milk for LESS THAN 2€
// RQL query ... (must possibly be encoded!)GET /orders?query=
and(eq(type,coffee),or(eq(ingredients,MILK),lt(price,2))
// RQL alternative query – FIQL (URI friendly) - ... GET /orders?query=
type==coffee;(ingredients==MILK,price=lt=2)
REST„search“
#WISSENTEILEN
// SUPER ADVANCED SEARCH: // All stores with// - employees older than 20 years// - who have soled more than 1000 coffee/day// - even if it was damnd hot outside (> 30 degree)
#WTHREST
„search“
#WISSENTEILEN
Filter, Sorting, Pagination
Super Advanced Queries
• teure Client-Server Roundtrips (n+1 oder mehr)• virtuelle Ressourcen (statisch? dynamisch?)
• GraphQLals Alternative unbedingt anschauen!
(* https://github.com/persvr/rql)
#WISSENTEILEN
Filter, Sorting, Pagination
GraphQL
• beliebige Abfragen via Objekt-Graph auf dem man navigiert• liefern des Abfrage-Results in einem einzigen Round-Trip
#WISSENTEILEN
// SUPER ADVANCED SEARCH: // All stores and their sales// - employees of age 20// - have sold at least 1000 coffee/day// - even if it was damnd hot (> 30 degree){
stores {namesales(unit: EURO) employees(age:20, soldCoffee:1000) {
...}
}}
REST„graphQL“
#WISSENTEILEN
REST... Status Codes
(see also: http://www.restpatterns.org/HTTP_Status_Codes/)
#WISSENTEILEN
Pro Tipp: Use them!
• 1xx: Hold on ...• 2xx: Here you go!• 3xx: Go away!• 4xx: You f#!?ed up!• 5xx: I f#!?ed up!
(http://restlet.com/http-status-codes-map)
Facebook „Always 200“ Anti-Pattern
HTTP Status Codes
(http://www.restpatterns.org/HTTP_Status_Codes)
#WISSENTEILEN
HTTP Status Codes
#WISSENTEILEN
// HTTP Status Codes: // signal that new order was created
// „Create new Resource“ of type orderPOST /orders HTTP/1.1[various other headers]
// Response with location header pointing to resourceHTTP/1.1. 201 CreatedLocation: http//restbucks.com/api/orders/1234
REST„Codes“
#WISSENTEILEN
// HTTP Status Codes: // signal that some work is going on
// Trigger some async workloadPOST /orders/... HTTP/1.1[various other headers]
// Response without payload, cause it‘s not yet calculatedHTTP/1.1. 202 Accepted
REST„Codes“
#WISSENTEILEN
// HTTP Status Codes: // signal that payload is empty
// DELETE order with id 1234DELETE /orders/1234 HTTP/1.1[various other headers]
// Order successfully deleted. No content by purposeHTTP/1.1. 204 No contentHTTP/1.1. 205 Reset content
REST„Codes“
#WISSENTEILEN
// HTTP Status Codes: // signal that payload is empty
// Retrieve all open ordersGET /orders?status=open HTTP/1.1[various other headers]
// There is no open order left. HTTP/1.1. 204 No content
REST„Codes“
#WISSENTEILEN
// HTTP Status Codes: // signal that there is more payload
// GET all orders on „page“ twoGET /orders?page=4 HTTP/1.1[various other headers]
// Response with success code and links for navigationHTTP/1.1. 206 Partial contentLink: <http://.../orders?page=1>; rel= „first“
<http://.../orders?page=3>; rel= „prev“, ...
REST„Codes“
#WISSENTEILEN
// HTTP Status Codes: // signal that payload is empty
// Ask for order with id 1234GET /orders/1234 HTTP/1.1[various other headers]
// Could not find order with id 1234 HTTP/1.1. 204 No content
REST„Codes“
#WISSENTEILEN
// HTTP Status Codes: // signal that payload is empty
// Ask for order with id 1234GET /orders/1234 HTTP/1.1[various other headers]
// Could not find order with id 1234 HTTP/1.1. 404 Not foundHTTP/1.1. 410 Gone
REST„Codes“
#WISSENTEILEN
Manchmal kommt es anders, als man denk
• Code for Code: Status Code & Appliction Level Code• Message for People: Für Logs, Ausgaben, ...• Payload and Format: genormte Error-Payload Format
• Kein Stacktrace• Exception Mapper als Provider auf äußerster Ebene
HTTP Status Codes
#WISSENTEILEN
// HTTP Status Codes: // signal that there is a problem
// Error Responses: Use them wiselyHTTP/1.1 400 Bad Request (unknown/generic status)HTTP/1.1 401 Unauthorized (btw: means unauthenticated)HTTP/1.1 403 Forbidden (btw: means unauthorized)HTTP/1.1 404 Not Found (resource could not be found)HTTP/1.1 405 Method not … (POST, GET, ...)HTTP/1.1 409 Conflict (fixable conflict, e.g. version)HTTP/1.1 410 Gone (update cache)HTTP/1.1 412 Precondition …(If-* header not matching) HTTP/1.1 418 I‘am a teapot (Don‘t ask me for COFFEE!)
REST„Codes“
#WISSENTEILEN
// HTTP Status Codes: // JAX-RS Exception Handler
@Providerpublic class MyAppExceptionHandler implements
ExceptionMapper<MyAppException> {@Overridepublic Response toResponse(MyAppException exception) {
return Response.status(Status.BAD_REQUEST).entity(new ExceptionEntity(exception)).build();
}}
REST„Codes“
#WISSENTEILEN
// HTTP Status Codes: // signal that there is a problem
// Error Responses: Use them wiselyHTTP/1.1 429 To many requestHTTP/1.1 509 Bandwith limit exceeded
REST„Codes“
#WISSENTEILEN
// HTTP Status Codes: // Rate limit exceeded (e.g. Twitter)
HTTP/1.1 429 To many requests[various other headers]
{ "errors": [
{ "code": 88, "message": "Rate limit exceeded" }
] }
REST„Codes“
#WISSENTEILEN
// HTTP Status Codes: // Rate limit exceeded (e.g. Twitter)
HTTP/1.1 200 Ok[various other headers]
X-Rate-Limit-Limit: ... // rate limit ceilingX-Rate-Limit-Remaining: ... // for the next 15 minutesX-Rate-Limit-Reset: ... // in UTC epoch seconds
REST„Codes“
#WISSENTEILEN
REST... Caching
#WISSENTEILEN
Always remember: „The Web is your Friend“
• das Web bietet tolle Möglichkeiten zur „Skalierung“• RESTful Service nutzen das Web bzw. HTTP
• Client (Web Browser, REST Client, ...) • Proxy Caches („man in the middle cache“)• Content Delivery Networks (CDNs)
Caching
#WISSENTEILEN
// Caching in REST: // Expires-Header (HTTP 1.0)
HTTP/1.1 200 OkContent-Type: application/jsonExpires: Tue, 20 MAI 2017 12:00 GMT
{"id": "espresso", "displayName": "Espresso", "price": 3.20,...
}
REST„Cache“
„Hint, ok. Aber für wen eigentlich?“
#WISSENTEILEN
// Caching in REST: // Chache-Control (HTTP 1.1)
HTTP/1.1 200 OkContent-Type: application/jsonCache-Control: private, no-store, max-age=3600
{"id": "espresso", "displayName": "Espresso", "price": 3.20,...
}
REST„Cache“
„Only client sidecaching. Valid for
3600 sec. Must not be stored on disc.“
#WISSENTEILEN
// Caching in REST: // Revalidation & Condition GET
// Cache-Control + Last-Modified Header HTTP 1.1HTTP/1.1 200 OkContent-Type: application/jsonCache-Control: max-age=3600Last-Modified: Wed, 10 MAI 2017 12:00 GMT
{"id": "espresso", ...
}
REST„Cache“
#WISSENTEILEN
// Caching in REST: // Revalidation & Condition GET
// Conditional GET after Timeout (max-age)GET /products/123 HTTP/1.1If-Modified-Since: Wed, 10 MAI 2017 12:00 GMT
REST„Cache“
Modified since? No, 304 (Not Modified). Yes, 200 (Ok) plus
Data.
#WISSENTEILEN
// Caching in REST: // Revalidation & Condition GET
// Cache-Control + eTag Header HTTP 1.1HTTP/1.1 200 OkContent-Type: application/jsonCache-Control: max-age=3600eTag: "1234567890987654321"
{"id": "espresso", ...
}
REST„Cache“
#WISSENTEILEN
// Caching in REST: // Revalidation & Condition GET
// Conditional GET after Timeout (max-age)GET /products/123 HTTP/1.1If-Non-Match: "1234567890987654321"
REST„Cache“
Modified since? No, 304 (Not Modified). Yes, 200 (Ok) plus
Data.
#WISSENTEILEN
REST... Security
#WISSENTEILEN
REST„Security“
#WISSENTEILEN
Authentication vs. Authorization
• Authentication a.k.a. „Hotelrezeption“• Authorization a.k.a. „Zimmerschlüssel“
Security
#WISSENTEILEN
Authentication vs. Authorization
• 401 „Unauthorized“meint eigentlich „Unauthenticated“!
• 403 „Forbidden“meint eigentlich „ Unauthorized“!
Security
#WISSENTEILEN
REST„Security“
Server based Security
• Sessions• Skalierbarbeit• Cookies • CORS • CSRF
#WISSENTEILEN
REST„Security“
Token based Security
• Stateless• Token statt Cookie• Individual Expiration• Friend to Friend Permissions
#WISSENTEILEN
JSON Web Token
• neue, einfache Spec• sehr kompakt• Token plus public & private „Claims“
• digitale Signatur und/oder Encryption• als Bearer Token und für SSO
Security
#WISSENTEILEN
REST„Security“
#WISSENTEILEN
JSON Web Token & API Goals
1. Authorize Request2. Verify Sender3. Avoid Man in the Middle4. Expiration5. Request Cloning
Security
#WISSENTEILEN
REST„Security“
#WISSENTEILEN
REST„Security“
#WISSENTEILEN
REST„Security“
#WISSENTEILEN
REST„Security“
#WISSENTEILEN
REST„Security“// Security in REST:
// JSON Web Token
//Reusable verifier instanceJWTVerifier verifier = JWT
.require(Algorithm.RSA256((RSAKey)publicKey))
.withIssuer("http://myAuth.com/auth/")
.build();
DecodedJWT jwt = verifier.verify(token);String userId = jwt.getSubject();String userName = jwt.getClaim("name").asString();String email = jwt.getClaim("email").asString();
com.oauth.jwt
#WISSENTEILEN
REST... API Evolution
#WISSENTEILEN
Was ist das Problem?
• neue APIs• geänderte APIs• deprecaded APIs
• Payload / Parameter Syntax• Payload / Parameter Semantik
API Evolution
#WISSENTEILEN
Postel‘s Law a.k.a. robustness principle:
„Be conservative in what you do*, be liberal in what you acceptfrom others.“
Ben Morris Blog:
„REST APIs don‘t need a versioning strategy – they need a change strategy!“
API Evolution
(* do = change)
#WISSENTEILEN
Versionierung! Aber wie?
• gar nicht• gar nicht (via neue Ressourcen) • gar nicht (via erweiterbarer Datenformate)• Versionsnummer in der URL• Version Request Header• Content Negotiation
API Evolution
#WISSENTEILEN
REST„Version“// Evolution in REST:
// Multiple Resources
// GET all orders v1 GET /orders HTTP/1.1
// GET all neworders, oders are deprecatedGET /neworders HTTP/1.1
// GET all even newer orders, new orders are deprecatedGET /evennewerorders HTTP/1.1
#WISSENTEILEN
REST„Version“// Evolution in REST:
// Multiple Resources
// GET all orders v1 GET /orders HTTP/1.1
// GET all neworders, oders are deprecatedGET /neworders HTTP/1.1
// GET all even newer orders, new orders are deprecatedGET /orders HTTP/1.1
#WISSENTEILEN
REST„Version“// Evolution in REST:
// Backwards compability
// Versioning via adaptable data format{ "items" : [ {
"name" : "coffee","quantity" : 1,"size" : "large",
} ],"location" : ”take-away"
}
#WISSENTEILEN
REST„Version“// Evolution in REST:
// Backwards compability
// Versioning via adaptable data format{ "items" : [ {
"name" : "coffee","quantity" : 1,"size" : "large",”price" : ”4 USD",
} ],”total-price" : ”4 USD","location" : ”take-away"
}
#WISSENTEILEN
REST„Version“// Evolution in REST:
// Backwards compability
// Versioning via adaptable data format{ "items" : [ {
"name" : "coffee","quantity" : 1,“size" : "large",“price" : ”4 USD",
} ],”price" : ”4 USD","location" : ”take-away"
}
„Are you a tolerant reader?“
#WISSENTEILEN
REST„Version“// Evolution in REST:
// via URL
// Versioning via URL (default version)GET /api/orders/1234 HTTP/1.1
// Versioning via URL (version 1)GET /api/v1/orders/1234 HTTP/1.1
// Versioning via URL (version 2)GET /api/v2/orders/1234 HTTP/1.1
No way! This isn‘t a RESOURCE!
#WISSENTEILEN
REST„Version“// Evolution in REST:
// via HEADER
// Versioning via Header(default version)GET /orders/1234 HTTP/1.1
// Versioning via Custom Header GET /orders/1234 HTTP/1.1Api-version: 2.1
// Versioning via Accept HeaderGET /orders/1234 HTTP/1.1Accept: application/vnd.restbucks.orderservice.v2.1+json
No way! This isn‘t a “clickable“ URL!
For chaching: „Vary: Content-Type“
#WISSENTEILEN
REST„Version“// Evolution in REST:
// via URL and HEADER
// Versioning via Header(default version)GET /orders/1234 HTTP/1.1
// Versioning via URL (major) and header (minor) GET /orders/v2/1234 HTTP/1.1my-api-version: 2017-05-01
#WISSENTEILEN
REST„Hateoas“
„If the engine of application state (and hence theAPI) is not driven by hypertext, then it cannot beRESTful and cannot be a REST API.“
Roy Fielding
// Evolution in REST: // Hypermedia as the engins of// application state
#WISSENTEILEN
REST„Hateoas“
„A REST API should be entered with no priorknowledge beyond the initial URI ... From thatpoint on, all application state transitions must bedriven by the client selection of server-provideschoices ...“
Roy Fielding
// Evolution in REST: // Hypermedia as the engins of// application state
#WISSENTEILEN
REST„ Hateoas“// Evolution in REST:
// Hypermedia as the engins of// application state
POST /orders/ HTTP/1.1{ ... payload of order to create ... }
HTTP/1.1. 201 CreatedLocation: http://restbucks.com/api/orders/1234Link: <.../orders/1234>; rel=„cancel“
<.../orders/1234>; rel=„update“, <.../orders/1234>; rel=„delete“,<.../payment/1234>; rel=„pay“
#WISSENTEILEN
FAZIT
#WISSENTEILEN
„The very most important thing is thatyou have an API that your consumersfind consistent and usable. This is not necessarily the same thingas being 100% RESTful.“
#WISSENTEILEN
FRAGEN
? ? ?
Kontakt
LARS RÖWEKAMPCIO NEW TECHNOLOGIES
[email protected]+49 (0)441 4082 – 0
@mobileLarson@_openknowledge
OFFENKUNDIGGUT
#WISSENTEILEN
Bildnachweise
#97: © tomertu - shutterstock.com
All other pictures inside this presentation orginatefrom pixabay.com or were created by my own.
#WISSENTEILEN