@ArneLimburg @_openknowledge #WISSENTEILEN API Design – Beware of the versioning hell
@ArneLimburg @_openknowledge #WISSENTEILEN
API Design – Beware of the versioning hell
API Versioning | Arne Limburg
GRÜNE WIESE
Server
REST
Client
API Versioning | Arne Limburg
API DESIGN
Server
REST
Client
API Versioning | Arne Limburg
API FIRST DESIGN
Server
Client
API Versioning | Arne Limburg
API FIRST DESIGN
API Versioning | Arne Limburg
API FIRST DESIGN
Mapping
Schnittstelle
API Versioning | Arne Limburg
KLASSISCHE ARCHITEKTUR
Mapping
Schnittstelle
Backend
Frontend
Client
API Versioning | Arne Limburg
KLASSISCHE ARCHITEKTUR
Backend
Frontend
Client
API Versioning | Arne Limburg
KLASSISCHE ARCHITEKTUR
Mapping
Schnittstelle
API Versioning | Arne Limburg
ÜBERFLÜSSIGEN CODE VERMEIDEN
Mapping
Schnittstelle
API Versioning | Arne Limburg
SCHLANKE ARCHITEKTUR ZU BEGINN
Schnittstelle
API Versioning | Arne Limburg
ÄNDERUNG AM MODELL
Schnittstelle
API Versioning | Arne Limburg
VERSCHIEDENE MODELLE
Mapping
Schnittstelle
Schnittstelle
API Versioning | Arne Limburg
VERSCHIEDENE MODELLE
Mapping
API Versioning | Arne Limburg
VERSCHIEDENE MODELLE
Mapping
API Versioning | Arne Limburg
VERSCHIEDENE SCHNITTSTELLEN
Mapping
Mapping
API Versioning | Arne Limburg
VERSCHIEDENE SCHNITTSTELLEN
Mapping
API Versioning | Arne Limburg
VERSCHIEDENE SCHNITTSTELLEN
Mapping Mapping
Mapping Mapping
API Versioning | Arne Limburg
VERSCHIEDENE SCHNITTSTELLEN
Mapping Mapping
Mapping Mapping
API Versioning | Arne Limburg
DOMAIN DRIVEN DESIGN
„For most software projects, the primary focus should be on the domain and domain logic“
Eric Evans, Domain-Driven Design, Addison-Wesley, © Eric Evans, 2004
DOMÄNE
End User
Domain Expert
Technical Expert
Translation Ist auf Dauer teuer sogar sehr teuer
API Versioning | Arne Limburg
UBIQUITOUS LANGUAGE
API Versioning | Arne Limburg
End User
Domain Expert
Technical Expert
Fachsprache als Basis
Eindeutige Begriffe
Durchgängige Nutzung
API Versioning | Arne Limburg
DOMAIN DRIVEN DESIGN
„Complex Domain Design
should be based on a model “
Eric Evans, Domain-Driven Design, Addison-Wesley, © Eric Evans, 2004
API Versioning | Arne Limburg
DOMÄNENMODELL
Repräsentation der Domäne
Fachlich korrekt und konsistent
Weiterentwicklung durch alle Beteiligten
API Versioning | Arne Limburg
DOMÄNENMODELL
Repräsentation der Domäne
Fachlich korrekt und konsistent
Weiterentwicklung durch alle Beteiligten
„Das Domänenmodell ist das Bindeglied zwischen Domänenexperten und
Entwicklern“
Eric Evans, Domain-Driven Design, Addison-Wesley, © Eric Evans, 2004
API Versioning | Arne Limburg
VERSCHIEDENE MODELLE
Mapping
Schnittstelle
API Versioning | Arne Limburg
VERSCHIEDENE MODELLE
Mapping Mapping
Mapping Mapping
API Versioning | Arne Limburg
VERSCHIEDENE MODELLE
Mapping
Schnittstelle
API Versioning | Arne Limburg
SCHLANKE ARCHITEKTUR
Mapping
Schnittstelle
API Versioning | Arne Limburg
ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 à Liefert Addresse { street: { "name": "Poststraße", "number": "1", }, "city": "26122 Oldenburg" }
API Versioning | Arne Limburg
ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 Attribut hinzufügen { street: { "name": "Poststraße", "number": "1", "additionalAdressLine": "2. Obergeschoss" }, "city": "26122 Oldenburg" }
API Versioning | Arne Limburg
ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 Attribut hinzufügen { street: { "name": "Poststraße", "number": "1", "additionalAdressLine": "2. Obergeschoss" }, "city": "26122 Oldenburg" }
Besondere Anforderung an den Client:
Unbekannte Attribute ignorieren à
Tolerant Reader Pattern
API Versioning | Arne Limburg
TOLERANT READER PATTERN
Server schickt {
street: {
"name": "Poststraße",
"number": "1",
"additionalAdressLine":
"2. Obergeschoss"
}...
}
http://www.example.com/addresses/42
Client erwartet {
street: {
"name": "Poststraße",
"number": "1",
}...
}
API Versioning | Arne Limburg
ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 Attribut-Umbenennung { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", }, "city": "26122 Oldenburg" }
API Versioning | Arne Limburg
ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 à Abwärtskompatible Änderungen: Umbenennen durch Kopieren { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", }, "city": "26122 Oldenburg" }
API Versioning | Arne Limburg
MAGNANIMOUS WRITER PATTERN
Server schickt {
street: {
"name": "Poststraße",
"streetName": "Poststraße",
"number": "1",
"houseNumber": "1“
}...
}
http://www.example.com/addresses/42
Client erwartet {
street: {
"name": "Poststraße",
"number": "1",
}...
}
http://tenderware.blogspot.de/2011/05/magnanimous-writer.html
API Versioning | Arne Limburg
MAGNANIMOUS WRITER PATTERN
Server schickt {
street: {
"name": "Poststraße",
"streetName": "Poststraße",
"number": "1",
"houseNumber": "1“
}...
}
http://www.example.com/addresses/42
Client erwartet {
street: {
"streetName": "Poststraße",
"houseNumber": "1",
}...
}
http://tenderware.blogspot.de/2011/05/magnanimous-writer.html
API Versioning | Arne Limburg
MAGNANIMOUS WRITER PATTERN
Server erwartet
PUT http://www.example.com/addresses/42
Client schickt {
street: {
"name": "Poststraße",
"number": "1",
}...
}
http://tenderware.blogspot.de/2011/05/magnanimous-writer.html
„Be conservative in what you do,
Be liberal in what you expect“
Postels Law (John Postel)
API Versioning | Arne Limburg
MAGNANIMOUS WRITER PATTERN PUT http://www.example.com/addresses/42
Client schickt {
street: {
"name": "Poststraße",
"number": "1",
}...
}
http://tenderware.blogspot.de/2011/05/magnanimous-writer.html
Server erwartet {
street: {
"name": "Poststraße",
"streetName": "Poststraße",
"number": "1",
"houseNumber": "1“
}...
}
oder oder
API Versioning | Arne Limburg
MAGNANIMOUS WRITER PATTERN PUT http://www.example.com/addresses/42
Client schickt {
street: {
"streetName": "Poststraße",
"houseNumber": "1",
}...
}
http://tenderware.blogspot.de/2011/05/magnanimous-writer.html
Server erwartet {
street: {
"name": "Poststraße",
"streetName": "Poststraße",
"number": "1",
"houseNumber": "1“
}...
}
oder oder
API Versioning | Arne Limburg
MAGNANIMOUS WRITER UND XML http://www.example.com/.../street
à Abwärtskompatible Änderungen
<street>
<name>Poststraße</name>
<houseNumber>0815</...>
</customer>
<xs:schema xmlns:xs:="...">
<xs:complexType name="streetType">
<xs:sequence>
...
<xs:element
name="houseNumber"
type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
API Versioning | Arne Limburg
MAGNANIMOUS WRITER UND XML http://www.example.com/.../street
à Abwärtskompatible Änderungen à Version 1.1
<customer>
<name>Max Mustermann</name>
<houseNumber>0815</...>
<number>0815</number>
</customer>
<xs:sequence>
...
<xs:element ...
name="houseNumber“
minOccurs="0"/>
<xs:element ...
name="number“
minOccurs="0"/>
</xs:sequence>
API Versioning | Arne Limburg
MAGNANIMOUS WRITER UND XML http://www.example.com/.../street
à Abwärtskompatible Änderungen à Version 1.1
<customer>
<name>Max Mustermann</name>
<houseNumber>0815</...>
<number>0815</number>
</customer>
<xs:sequence>
...
<xs:element ...
name="houseNumber“
minOccurs="0"/>
<xs:element ...
name="number“
minOccurs="0"/>
<xs:any minOccurs="0"/>
<xs:anyAttribute
processContents="lax"/>
API Versioning | Arne Limburg
MAGNANIMOUS WRITER UND XML à Offizieller Versionssupport seit XML-Schema 1.1 <schema ... xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning">
<complexType name="street" vc:maxVersion="1.3">
...
</complexType>
<complexType name="street" vc:minVersion="2.0">
...
</complexType>
</schema>
API Versioning | Arne Limburg
ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 à Abwärtskompatible Änderungen: Umbenennen durch Kopieren { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", }, "city": "26122 Oldenburg" }
Geht da noch mehr?
API Versioning | Arne Limburg
ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 à Zusammenführen und Teilen von Attributen { street: { ... "streetName": "Poststraße", "houseNumber": "1", "addressLine1": "Poststraße 1", } ... }
API Versioning | Arne Limburg
ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 à Herausforderungen: Zusammenführen von Attributen { street: { ... "streetName": "Poststraße", "houseNumber": "1", "addressLine1": "Poststraße 1", } ... }
API Versioning | Arne Limburg
ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 à Herausforderungen: Teilen von Attributen { street: { ... "addressLine1": "Poststraße 1", } "city": "26122 Oldenburg", "zipCode": "26122", "cityName": "Oldenburg" }
API Versioning | Arne Limburg
ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 à Herausforderungen: Ebene von Attributen ändern { street: { ... "addressLine1": "Poststraße 1" } "addressLine1": "Poststraße 1", ... }
API Versioning | Arne Limburg
ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 à Herausforderungen: Ebene von Attributen ändern { ... "zipCode": "26122", "cityName": "Oldenburg", "location": { "zipCode": "26122", "cityName": "Oldenburg" } }
API Versioning | Arne Limburg
ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 à Herausforderungen: Ebene von Attributen ändern { ... "zipCode": "26122", "cityName": "Oldenburg", "location": { "zipCode": "26122", "cityName": "Oldenburg" } }
Bei jeder Modelländerung muss eine Migrationsstrategie
einbezogen werden!
API Versioning | Arne Limburg
ABWÄRTSKOMPATIBILITÄT { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", "addressLine1": "Post... 1", "addressLine2": "" }
"addressLine1": "Poststraße 1", "addressLine2": "", "city": "26122 Oldenburg", "zipCode": "26122", "cityName": "Oldenburg", "location": { "zipCode": "26122", "cityName": "Oldenburg" } }
http://www.example.com/v1/addresses/42 à Bisher nur abwärtskompatible Änderungen
API Versioning | Arne Limburg
DOMÄNENMODELL ALS API
Schnittstelle
API Versioning | Arne Limburg
ABWÄRTSKOMPATIBILITÄT { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", "addressLine1": "Post... 1", "addressLine2": "" }
"addressLine1": "Poststraße 1", "addressLine2": "", "city": "26122 Oldenburg", "zipCode": "26122", "cityName": "Oldenburg", "location": { "zipCode": "26122", "cityName": "Oldenburg" } }
http://www.example.com/v1/addresses/42 à Viele Attribute deprecated
API Versioning | Arne Limburg
VERSIONSSPRUNG { street: { "name": "Poststraße", "streetName": "Poststraße", "number": "1", "houseNumber": "1", "addressLine1": "Post... 1", "addressLine2": "" }
"addressLine1": "Poststraße 1", "addressLine2": "", "city": "26122 Oldenburg", "zipCode": "26122", "cityName": "Oldenburg", "location": { "zipCode": "26122", "cityName": "Oldenburg" } }
http://www.example.com/v1/addresses/42 à Bisher nur abwärtskompatible Änderungen
API Versioning | Arne Limburg
INKOMPATIBLE ÄNDERUNG http://www.example.com/v2/addresses/42 à Versionssprung { "addressLine1": "Poststraße 1", "addressLine2": "", "location": { "zipCode": "26122", "cityName": "Oldenburg" } }
• Umbennen von Ressourcen à Http-Status-Code 301 „Moved Permanently“
• Semantische Änderung von Attributen à Anderen Namen vergeben
• Neue Version hat anderes Verhalten à Neue Schnittstelle
• PUT zum Setzen leerer Attribute à Unterscheidung zwischen nicht vorhanden und empty
WEITERE HERAUSFORDERUNGEN
API Versioning | Arne Limburg
• Über URL-Pfad /v2/addresses
• Über Query-Parameter /addresses?version=v2
• Über Version-Header 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
API Versioning | Arne Limburg
API Versioning | Arne Limburg
DOMÄNENMODELL ALS API
Schnittstelle Schnittstelle
{ street: {
"name": "Poststraße",
"streetName": "Poststraße",
"number": "1",
"houseNumber": "1",
"addressLine1": "Post... 1",
"addressLine2": ""
}
"addressLine1": "Poststraße 1",
"addressLine2": "",
"city": "26122 Oldenburg",
"zipCode": "26122",
"cityName": "Oldenburg",
"location": {
"zipCode": "26122",
"cityName": "Oldenburg"
}
}
{
"addressLine1": "Poststraße 1",
"addressLine2": "“,
"location": {
"zipCode": "26122",
"cityName": "Oldenburg"
}
}
V1 V2-SNAPSHOT
API Versioning | Arne Limburg
DOMÄNENMODELL ALS API Schnittstelle Schnittstelle
{ street: {
"name": "Poststraße",
"streetName": "Poststraße",
"number": "1",
"houseNumber": "1",
"addressLine1": "Post... 1",
"addressLine2": ""
}
...
}
{
"addressLine1": "Poststraße 1",
"addressLine2": "“,
"city": {
"zipCode": "26122",
"cityName": "Oldenburg"
}
}
V1 V3-SNAPSHOT
Schnittstelle
{ "addressLine1": "Poststraße 1",
"addressLine2": "“,
"location": {
"zipCode": "26122",
"cityName": "Oldenburg"
},
"city": {
"zipCode": "26122",
"cityName": "Oldenburg"
}} V2
API Versioning | Arne Limburg
FAZIT Schnittstelle Schnittstelle
{ street: {
"name": "Poststraße",
"streetName": "Poststraße",
"number": "1",
"houseNumber": "1",
"addressLine1": "Post... 1",
"addressLine2": ""
}
...
}
{
"addressLine1": "Poststraße 1",
"addressLine2": "“,
"city": {
"zipCode": "26122",
"cityName": "Oldenburg"
}
}
V1 V3-SNAPSHOT
Schnittstelle
{ "addressLine1": "Poststraße 1",
"addressLine2": "“,
"location": {
"zipCode": "26122",
"cityName": "Oldenburg"
},
"city": {
"zipCode": "26122",
"cityName": "Oldenburg"
}} V2
Änderungen innerhalb einer Version sind fachlich
Migrations-Strategie für jede Attribut-Änderung
Mapping zwischen Versionen ist automatisierbar
Domänenmodell reflektiert immer aktuelle API
API Versioning | Arne Limburg
FRAGEN & DISKUSSION
? ? ?