APIs sind heutzutage der Kern von modernen Anwendungen. Wenn sie gut designt sind, können mit ihnen ohne großen Mehraufwand neue Geschäftsfelder erschlossen und neue oder geänderte Dienstleistungen angeboten werden.
Zudem werden immer mehr Systeme als Microservices-Architekturen aufgebaut, wodurch der Stellenwert auch von guten internen APIs wächst.
Je mehr Nutzer ein API hat und je weniger der Anbieter eines APIs seine Consumer kennt, um so wichtiger wird es, leicht verständliche und leicht zu verwendende APIs anzubieten, die auch sinnvoll weiterentwickelt werden können. Wie müssen sich Clients verhalten, damit sie die Schnittstelle auch bei Weiterentwicklung reibungslos verwenden können? Ansätze wie API First und Consumer-driven Contracts versuchen, diesen Anforderungen gerecht zu werden. Diese werden in dem Workshop an praktischen Beispielen vorgestellt. Zudem wird gezeigt, wie eine Schnittstelle abwärtskompatibel weiterentwickelt werden kann, ohne sich in der Versionierungshölle zu verlieren.
2. ÜBER MICH
Microservices maßgeschneidert | Arne Limburg
• Enterprise Architect bei der open knowledge GmbH
• Themen
• Microservices
• Domain Driven Design
• APIs
• Architektur
• Coaching
• Technologie (Java EE / Jakarta EE)
Arne Limburg
3. ÜBER OPEN KNOWLEDGE
Titel der Präsentation | Name des Sprechers
Branchenneutrale Softwareentwicklung und IT-Beratung
6. #WISSENTEILEN
// Retrieve all products
GET /products
// What about searching, filtering, pagination?
// Retrieve single product
GET /products/1234
// What about buying it?
// i.e. putting to shopping cart, payment, etc.
REST
„URLs“
8. #WISSENTEILEN
// Retrieve all customers
GET /customers
// Retrieve single customer with ID 1234
GET /customers/1234
REST
„URLs“
9. #WISSENTEILEN
// Retrieve single customer with id 1234
GET /customers/1234
// Retrieve all addresses of customer 1234
GET /customers/1234/addresses
// Retrieve address 5 of customer 1234
GET /customers/1234/addresses/5
REST
„root“
10. #WISSENTEILEN
// Retrieve all addresses of customer 1234
GET /customers/1234/addresses
// vs.
// Retrieve all addresses of customer 1234
GET /addresses/?customerNumber=1234
REST
„root“
11. #WISSENTEILEN
// Path parameter for identifier
GET /customers/1234
// Query parameter for queries (optional)
GET /customers/?status=verified
// Header parameter for platform (optional)
GET /customers/1234
Accept-Language: de-DE
REST
„param“
12. #WISSENTEILEN
// Retrieve all addresses of customer 1234
GET /customers/1234/addresses
// vs.
// Retrieve all addresses of customer 1234
GET /addresses/?customerNumber=1234
REST
„root“
14. #WISSENTEILEN
// register customer
POST /customers
{ ... initial customers data ... }
// read customer e.g. to check status
GET /customers/1234
// change customer
PUT /customers/1234
{ ... some changes ... }
// remove customer
DELETE /customers/1234
REST
„method“
15. #WISSENTEILEN
// „Create new customer“.
POST /customers
// Is this allowed? Guess not. Is it?
POST /customers/1234
// „Change customer“. I‘am sure! But wait ...“
PUT /customers/1234
// „Change customer“, too? Isn‘t it?
PATCH /customers/1234
REST
„method“
16. #WISSENTEILEN
POST vs. PUT vs. PATCH
POST
erzeugt 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
17. #WISSENTEILEN
// Creates customer. Returns ID 1234
POST /customers
{ ... payload for 1234 ... }
// Hmmm, updates customer 1234? Creates new customer?
POST /customers
{ ... payload for 1234 ... }
REST
„method“
18. #WISSENTEILEN
// Changes customer with ID 1234
PUT /customers/1234
{ ... changes for 1234 ... }
// Hmmm, will be ignored?
PUT /customers/1234
{ ... changes for 1234, e.g. add e-mail address ... }
// Or additional changes?
PUT /customers/1234
{ ... changes for 1234, e.g. add more e-mail addresses ... }
REST
„method“
20. #WISSENTEILEN
// Changes customer with ID 1234
PUT /customers/1234
{ ... changes for 1234 ... }
// Same as PUT? Mayby not!
PATCH /customers/1234
{ ... changes for 1234 ... }
// Same as PUT? Is this what i expect?
GET /customers/1234?status=verified or
GET /customers/1234/setVerified
REST
„method“
21. #WISSENTEILEN
SAFE / IDEMPOTENT Methods
SAFE*
keine Änderung an der Ressource
IDEMPOTENT**
einmalige Änderung an der Ressource-Repräsentation
mehrfache Wiederholung führt immer zum selben Ergebnis
* GET, HEAD, OPTIONS
** GET, HEAD, OPTIONS, PUT, DELETE
23. #WISSENTEILEN
// FILTERING:
// List of paid orders (2015-12-20)
// Common Style
GET /orders?date=20151220&status=payed HTTP 1.1
REST
„filter“
24. #WISSENTEILEN
// FILTERING:
// Details of order 3 (product, date, ...)
// Facebook Style
GET /orders/3?fields=product,date,status HTTP/1.1
GET /orders/3?fields=item.product,date,status HTTP/1.1
// LinkedIn Style
GET /orders/3:(product, date, status) HTTP/1.1
REST
„filter“
25. #WISSENTEILEN
// FILTERING:
// Details of order 3
// without date, status
GET /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?
26. #WISSENTEILEN
// FILTERING:
// Details of order 3
// using PREFER HEADER for response payload definition
GET /orders/3 HTTP/1.1
Content-Type: application/json
Prefer: return=compact-format
HTTP 1.1 200 OK
Content-Type: application/json; charset=utf-8
Preference-Applied: return=compact-format
REST
„filter“
27. #WISSENTEILEN
// SORTING:
// orders sorted (date ↓ /item ↑)
// SQL alike style
GET /orders?sort=date+DESC,item+ASC HTTP/1.1
// Sort and asc/desc combination, ascending as default
GET /orders?sort=date,item&desc=date HTTP/1.1
// use prefix „-“ for descending, ascending as default
GET /orders?sort=-date,item HTTP/1.1
REST
„sorting“
28. #WISSENTEILEN
// FILTERING & SORTING:
// orders of „today“ sorted by ...
// long version
GET /orders?status=open
&date_from=20170510&date_to=20170510
&fields=product,status,time&sort=-time,product
// short and readable version
GET /orders/open_orders_of_today
GET /open_orders_of_today
REST
„filter&sort“
29. #WISSENTEILEN
// Pagination a.k.a. „Limiting“:
// 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?
30. #WISSENTEILEN
// Pagination a.k.a. „Limiting“:
// return page 4 of orders
// get “page 4“ and info about PREV/NEXT
GET /orders?offset=10&limit=5 HTTP/1.1
// Response with success code and link header for
// navigation purpose
HTTP/1.1. 200 OK
Link: <.../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“
31. #WISSENTEILEN
// Pagination a.k.a. „Limiting“:
// 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 purpose
HTTP/1.1. 200 OK
Link: <.../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“
32. #WISSENTEILEN
// FULL TEXT SEARCH:
// Fulltext search for coffee
// Global style via virtual resource
GET /searches?q=coffee HTTP/1.1 oder
// Scoped style
GET /orders/searches?q=coffee HTTP/1.1
GET /orders?q=coffee HTTP/1.1
REST
„search“
„GET vs.
POST
„GET vs.
POST
33. #WISSENTEILEN
// ADVANCED SEARCH:
// Coffee WITH milk for 2€
// Query for ...
GET /orders?type=coffee&ingredient=milk&price=2
REST
„search“
BTW: AND or OR or
AND/OR?
34. #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“?
35. #WISSENTEILEN
// ADVANCED SEARCH:
// Coffee WITH milk or 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“
38. #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
39. #WISSENTEILEN
// Caching in REST:
// Expires-Header (HTTP 1.0)
HTTP/1.1 200 Ok
Content-Type: application/json
Expires: Mon, 24 SEP 2018 12:00:01 GMT
{
"id": "1",
"firstName": "Max",
"lastName": "Mustermann",
... ...
}
REST
„Cache“
„Hint, ok. Aber für
wen eigentlich?“
41. #WISSENTEILEN
// Caching in REST:
// Cache-Control (HTTP 1.1)
HTTP/1.1 200 Ok
Content-Type: application/json
Cache-Control: private, no-store, max-age=3600
{
"id": "1",
"firstName": "Max",
"lastName": "Mustermann",
...
}
REST
„Cache“
„Only client side
caching. Valid for
3600 sec. Must not
be stored on disc.“
42. #WISSENTEILEN
CACHING
Revalidation & Conditional GET (HTTP 1.1)
• Revalidation zur Prüfung, ob Cache-Daten wirklich invalide
• Server sendet speziellen Header zur Prüfung zurück
• Last-Modified
• Etag
43. #WISSENTEILEN
// Caching in REST:
// Revalidation & Conditional GET
// Cache-Control + Last-Modified Header HTTP 1.1
HTTP/1.1 200 Ok
Content-Type: application/json
Cache-Control: max-age=3600
Last-Modified: Wed, 10 MAI 2017 12:00:01 GMT
{
"id": "1",
...
}
REST
„Cache“
44. #WISSENTEILEN
// Caching in REST:
// Revalidation & Conditional GET
// Conditional GET after Timeout (max-age)
GET /products/123 HTTP/1.1
If-Modified-Since: Wed, 10 MAI 2017 12:00:01 GMT
REST
„Cache“
Modified since? No,
304 (Not Modified).
Yes, 200 (Ok) plus
Data.
46. #WISSENTEILEN
// Caching in REST:
// Revalidation & Condition GET
// Conditional GET after Timeout (max-age)
GET /products/123 HTTP/1.1
If-None-Match: "1234567890987654321"
REST
„Cache“
Modified since? No,
304 (Not Modified).
Yes, 200 (Ok) plus
Data.
47. #WISSENTEILEN
// Optimistic Locking
// Conditional PUT
// Conditional PUT
PUT /customers/1234 HTTP/1.1
If-Match: "1234567890987654321"
REST
„Cache“
Modified in between?
No, 200 (OK).
Yes, 412
(Precondition Failed)
48. #WISSENTEILEN
// Optimistic Locking
// Conditional PUT
// PUT ohne Precondition
PUT /customers/1234 HTTP/1.1
REST
„Cache“
Force Optimistic
Locking:
428 (Precondition
Required)
50. #WISSENTEILEN
Headers
HTTP Header Parameter
• Meta Daten für Request / Response
• Accept: ich komme mit Format xyz klar
• Content-Type: ich sende dir Format xyz
• Location-Header: genauere/mehr Info zu „mir“ unter ...
• Link-Header: siehe auch unter ...
• Authorization*-Header: Auth Tokens, Basic Auth ...
• X-Custom-Header: ich habe da noch was für dich ...
{?}
52. #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)
53. #WISSENTEILEN
// HTTP Status Codes:
// signal that new order was created
// „Create new Resource“ of type order
POST /customers HTTP/1.1
[various other headers]
// Response with location header pointing to resource
HTTP/1.1. 201 Created
Location: http://…/customers/1234
REST
„Codes“
54. #WISSENTEILEN
// HTTP Status Codes:
// signal that some work is going on
// Trigger some async workload
POST /customers/
HTTP/1.1
[various other headers]
// Response without payload, cause it‘s not yet calculated
HTTP/1.1. 202 Accepted
REST
„Codes“
55. #WISSENTEILEN
// HTTP Status Codes:
// signal that payload is empty
// DELETE customer with id 1234
DELETE /customers/1234 HTTP/1.1
[various other headers]
// Customer successfully deleted. No content by purpose
HTTP/1.1. 204 No content
HTTP/1.1. 205 Reset content
REST
„Codes“
56. #WISSENTEILEN
// HTTP Status Codes:
// signal that payload is empty
// Retrieve all verified customers
GET /customers?status=verified HTTP/1.1
[various other headers]
// There is no verified customer left.
HTTP/1.1. 204 No content
REST
„Codes“
57. #WISSENTEILEN
// HTTP Status Codes:
// signal that there is more payload
// GET all orders on „page“ two
GET /customers?page=4 HTTP/1.1
[various other headers]
// Response with success code and links for navigation
HTTP/1.1. 206 Partial content
Link: <http://.../customers?page=1>; rel= „first“
<http://.../customers?page=3>; rel= „prev“,
...
REST
„Codes“
58. #WISSENTEILEN
// HTTP Status Codes:
// signal that could not find order
// Ask for customer with id 1234
GET /customers/1234 HTTP/1.1
[various other headers]
// Could not find customer with id 1234
HTTP/1.1. 404 Not found
REST
„Codes“
59. #WISSENTEILEN
// HTTP Status Codes:
// signal that there is a limit problem
// Error Responses: Use them wisely
HTTP/1.1 429 To many request
HTTP/1.1 509 Bandwith limit exceeded
REST
„Codes“
60. #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“
61. #WISSENTEILEN
// HTTP Status Codes:
// Rate limit exceeded (e.g. Twitter)
HTTP/1.1 200 Ok
[various other headers]
X-Rate-Limit-Limit: ... // rate limit ceiling
X-Rate-Limit-Remaining: ... // for the next 15 minutes
X-Rate-Limit-Reset: ... // in UTC epoch seconds
REST
„Codes“
62. #WISSENTEILEN
// HTTP Status Codes:
// signal that the payload is invalid
// Change customer with id 1234
PUT /customers/1234 HTTP/1.1
[various other headers]
// Some content is invald
HTTP/1.1. 400 Bad Request
REST
„Codes“
63. #WISSENTEILEN
// HTTP Status Codes:
// Bad request
// - Validation error with problem+json
HTTP/1.1 400 Bad request
Content-Type: application/problem+json
[various other headers]
{
"type": "/problems/validation-error",
"title": "Your request parameters didn't validate.",
"status": 400,
"detail": "...",
"instance": "orders/1234"
}
REST
„Codes“
64. #WISSENTEILEN
// HTTP Status Codes:
// Bad request
// - Validation error with problem+json
HTTP/1.1 400 Bad request
Content-Type: application/problem+json
[various other headers]
{
"type": "/problems/validation-error",
"title": "Your request parameters didn't validate.",
...
"invalid-params": [
{ "path": "firstName",
"message": "firstName is mandatory" } ] }
Custom Extension for
Problem JSON
REST
„Codes“
65. #WISSENTEILEN
Manchmal kommt es anders, als man denk
• Code for Code: Status Code & Application Level Code
• Message for People: Für Logs, Ausgaben, ...
• Payload and Format: genormte Error-Payload Format
HTTP Status Codes
66. #WISSENTEILEN
// „Create new customer“.
POST /customers
Content-Type: application/json
// Is this allowed? Guess not. Is it?
POST /customers/1234
Content-Type: application/json
// „Change customer“. I‘am sure! But wait ...“
PUT /customers/1234
Content-Type: application/json
// „Change customer“, too? Isn‘t it?
PATCH /customers/1234
Content-Type: application/json
REST
„method“
67. #WISSENTEILEN
// HTTP Status Codes:
// Which patch should be used
HTTP/1.1 415 Unsupported Media Type
Content-Type: application/problem+json
[various other headers]
{
"type": "/problems/unsupported-media-type",
"detail": "supported media types are
application/merge-patch+json or
application/json-patch+json",
}
REST
„Payload“
71. #WISSENTEILEN
„Leonard Richardson proposed a
classification for services on the Web.
Leonard’s model promotes three levels of
service maturity based on a service’s
support for URIs, HTTP, and hypermedia!“
(Quelle: „REST in Practice“)
74. Titel der Präsentation | Name des Sprechers
RICHARTSON MATURITY MODEL
Level 0
• a.k.a. „Swamp of PoX“:
• HTTP als Transportsystem
• „RPC“-Style
• eine URI
• eine HTTP Methode (meist POST)
• Parameter und Rückgabe als Payload (XML/JSON/TEXT)
76. Titel der Präsentation | Name des Sprechers
RICHARTSON MATURITY MODEL
Level 1
• Aufbrechen des monolithischen Endpoints aus Level 0 in unterschiedliche
Ressourcen (a.k.a. Nomen), die gezielt angesprochen werden können.
77. Titel der Präsentation | Name des Sprechers
RICHARTSON MATURITY MODEL
Level 1
• a.k.a. „Resources“
• Individuelle Ressourcen statt Service Endpoint
• mehrere URIs
• ein oder zwei HTTP Methode (meist POST/GET)
• Parameter als Query-Parameter oder Payload
• Rückgabe als Payload (XML/JSON/TEXT)
79. Titel der Präsentation | Name des Sprechers
RICHARTSON MATURITY MODEL
Level 2
• Einführen verschiedener „Verben“, um gleiche Situationen mit den selben
Mechanismen behandeln zu können und so unnötige Varianten zu vermeiden.
80. Titel der Präsentation | Name des Sprechers
RICHARTSON MATURITY MODEL
Level 2
• a.k.a. „Verbs“
• „passende“ HTTP Methoden statt nur POST & GET
• mehrere URIs
• mehrere HTTP Methoden
• Rückgabe als Payload & Status Codes
82. Titel der Präsentation | Name des Sprechers
RICHARTSON MATURITY MODEL
Level 3
• Einführen von „Auffindbarkeit“, um so einen Mechanismus anzubieten, der das
Protokoll selbsterklärend(er) macht.
83. Titel der Präsentation | Name des Sprechers
RICHARTSON MATURITY MODEL
Level 3
• a.k.a. „Hypermedia“
• selbsterklärendes System
• nur eine Einstiegs-URI bekannt
• keine weiteren festen URIs
• Rückgabe als Liste von neuen „Möglichkeiten“
85. #WISSENTEILEN
„If the engine of application state (and
hence the API) is not driven by hypertext,
then it cannot be RESTful and cannot be a
REST API. Period. Is there some broken
manual somewhere that needs to be
fixed?“
Roy Fielding
86. #WISSENTEILEN
„A REST API should be entered with no
prior knowledge beyond the initial URI ...
From that point on, all application state
transitions must be driven by the client
selection of server-provides choices ...“
Roy Fielding
87. Titel der Präsentation | Name des Sprechers
RICHARTSON MATURITY MODEL
/orders/...
POST /orders { order payload }
http/1.1 201 Created
Location: ...
Link: cancel operation
update operation
delete operation
pay operation
C
O
N
S
U
M
E
R
O
R
D
E
R
S
88. Titel der Präsentation | Name des Sprechers
RICHARTSON MATURITY MODEL
/orders/...
/payments/...
http/1.1 201 Created
Location: ...
Link: http://<status operation>
http://<update operation>
http://<delete operation>
http://<pay operation>
GET
PUT
DELETE
POST
O
R
D
E
R
P
A
Y
89. #WISSENTEILEN
REST
„Hateoas“ v1
// Richardson Maturity Model:
// Hypermedia as the engine
// of application state
POST /orders/ HTTP/1.1
{ ... payload of order to create ... }
HTTP/1.1. 201 Created
Location: http://restbucks.com/api/orders/1234
Link: <.../orders/1234>; rel=„cancel“
<.../orders/1234>; rel=„update“,
<.../orders/1234>; rel=„delete“,
<.../payment/1234>; rel=„pay“
90. #WISSENTEILEN
// Aber wie bilde ich Relationen ab?
// the „naive“ way
// all customers
{
[
{ "id":"001", "for":"arne", ..., "addresses":[ ...] },
{ "id":"002", "for":"lars", ..., "addresses":[ ...] },
...
]
}
REST
„relation“
91. #WISSENTEILEN
// Aber wie bilde ich Relationen ab?
// the „naive“ way
// all customers
{
[
{ "id":"001", "for":"arne", ..., "addresses":[ ...] },
{ "id":"002", "for":"lars", ..., "addresses":[ ...] },
...
]
}
REST
„relation“
Benötige ich die Info hier wirklich?
92. #WISSENTEILEN
// Aber wie bilde ich Relationen ab?
// the „linked“ way
// all customers
{
[
{ "id":"001", "for":"arne", ..., "address_refs":[...]},
{ "id":"002", "for":"lars", ..., "address_refs":[...] },
...
]
}
REST
„relation“
https://..../customers/002/addresses/1
https://..../customers/002/addresses/2
Benötige ich weitere Infos?
93. #WISSENTEILEN
// Aber wie bilde ich Relationen ab?
// the „linked“ way
// all customers
{
[
{ "id":"001",
"for":"lars",
...,
"addresses_refs":[...],
"addresses_count" : 2
]
}
REST
„relation“
94. #WISSENTEILEN
// Aber wie bilde ich Relationen ab?
// the „linked“ way
// all customers
{
[
{ "id":"001",
"for":"lars",
"for_ref ": "http://.../customers/12",
...,
"addresses_refs":[...],
"addresses_count" : 2
]}
REST
„relation“
95. #WISSENTEILEN
// Aber wie bilde ich Relationen ab?
// the „linked“ way
// all customers
{
[
{ "id":"001", "for":"arne", ..., "address":[
{
"href": "http://.../customers/001/addresses/1"
}
]},
...
]
}
REST
„relation“
Welche Syntax hilft dem Consumer?
106. Tolerant Reader Pattern
Tolerant gegenüber unbekannten Feldern
Umgang mit x-extensible-enum
http://zalando.github.io/restful-api-guidelines
Tolerant gegenüber unbekannten Statuscodes
HTTP Status 301 folgen
112. Und was ist, wenn der Client kein
Tolerant Reader ist?
113. PROJEKTIONEN
// Client kann entscheiden, welche Felder er bekommen möchte
// Facebook Style
GET /addresses/3?fields=street,city
GET /addresses/3?fields=street.name,street.number,city
// LinkedIn Style
GET /addresses/3?fields=street:(name,number),city
114. OK, so soll sich
der Client verhalten.
Aber was ist mit dem Server?
115. Photo by Irene Fertik, USC News Service. Copyright 1994, USC.
„Be conservative in what you do,
Be liberal in what you accept
from others“
RFC 793, Robustness Principal (John Postel)
116. Es darf nichts entfernt werden
Keine Veränderung von Verarbeitungsregel
Optionales darf nie Required werden
http://zalando.github.io/restful-api-guidelines
Alles was hinzugefügt wird, muss optional sein
141. PIPELINE TO DEPLOY TO STAGE
Execute
Own
Provider
Tests
Generate
Consumer
Contract
Execute
Depending
Provider
Tests
Deploy
to
Stage
142. PIPELINE TO DEPLOY TO STAGE
Execute
Own
Provider
Tests
Generate
Consumer
Contract
Execute
Depending
Provider
Tests
Deploy
to
Stage
Achtung:
Abwärtskompatibilität ist
trotzdem notwendig!
143. BREAKING CHANGE VOM PROVIDER
Execute
Own
Provider
Tests
Generate
Consumer
Contract
Execute
Depending
Provider
Tests
Deploy
to
Stage
144. BREAKING CHANGE VOM CONSUMER
Execute
Own
Provider
Tests
Generate
Consumer
Contract
Execute
Depending
Provider
Tests
Deploy
to
Stage
149. Version 2.0
ist nur inkompatibel zu 1.0!
Version 2.0 ist identisch zu 1.x!
Das erleichtert das Mapping
zwischen den Versionen!
150. Ein solcher Versionssprung ist
nicht anforderungsgetrieben,
sondern viel besser und
langfristiger planbar
151. Wenn eine neue Version
nicht auf die alte abbildbar ist,
ist es keine neue Version,
sondern eine neue Schnittstelle!
152. • Über URL-Pfad
/v2/addresses
• Über Query-Parameter
/addresses?version=v2
• Über Version-Header
X-Api-Version: v2
• Über Version-Attribut am Media-Type
application/xml;version=v2
• Über Media-Type
application/vnd.de.openknowledge+v2+json
ERMITTELN DER VERSION
163. KONTAKT
Titel der Präsentation | Name des Sprechers
ARNE LIMBURG,
ENTERPRISE ARCHITECT
arne.limburg@openknowledge.de
+49 (0)441 40820
OFFENKUNDIGGUT