SlideShare ist ein Scribd-Unternehmen logo
1 von 77
Downloaden Sie, um offline zu lesen
API EXPAND CONTRACT
@ArneLimburg
ÜBER MICH
Arne Limburg – Lead Architect
@ArneLimburg
• APIs
• Microservices
• Domain Driven Design
• Architektur
• Coaching
• Technologie (Java EE / Jakarta EE)
OPEN KNOWLEDGE GmbH
Wir realisieren Enterprise-, Web- und Cloud-Anwendungen unter anderem für
Kunden aus den Bereichen Energie, Telekommunikation, Logistik, Industrie,
Versicherungs- sowie Bankwesen.
Strategisch, technologisch und methodisch sind wir kompetenter Partner für die
digitale Transformation von Geschäftsprozessen.
Wir entwickeln digitale Produkte und Services im Mittelstand sowie im Konzern.
Warum Kunden uns schätzen:
„Wir sind neugierig, wie unsere Kunden arbeiten. Uns
treibt an, Auftraggeber erfolgreicher und handlungsfähiger
zu machen.”
Softwarearchitektur &
- entwicklung
Strategie- &
Technologieberatung
Digitale Produkte &
Automatisierung
EXPAND & CONTRACT
TAB_ADDRESS
ADR_STREET
ADR_NUMBER
…
ALTER TABLE RENAME COLUMN ADR_NUMBER TO ADR_HOUSE_NUMBER
TAB_ADDRESS
ADR_STREET
ADR_HOUSE_NUMBER
…
public class Address {
@Column(name
= "ADR_NUMBER")
private String houseNumber;
…
}
ALTER TABLE RENAME COLUMN ADR_NUMBER TO ADR_HOUSE_NUMBER
TAB_ADDRESS
ADR_STREET
ADR_NUMBER
…
public class Address {
@Column(name
= "ADR_NUMBER")
private String houseNumber;
…
}
ALTER TABLE RENAME COLUMN ADR_NUMBER TO ADR_HOUSE_NUMBER
TAB_ADDRESS
ADR_STREET
ADR_HOUSE_NUMBER
…
public class Address {
@Column(name
= "ADR_NUMBER")
private String houseNumber;
…
}
ALTER TABLE RENAME COLUMN ADR_NUMBER TO ADR_HOUSE_NUMBER
TAB_ADDRESS
ADR_STREET
ADR_HOUSE_NUMBER
…
public class Address {
@Column(name
= "ADR_HOUSE_NUMBER")
private String houseNumber;
…
}
ALTER TABLE RENAME COLUMN ADR_NUMBER TO ADR_HOUSE_NUMBER
UNTERBRECHUNGSFREI?
TAB_ADDRESS
ADR_STREET
ADR_NUMBER
…
public class Address {
@Column(name
= "ADR_NUMBER")
private String houseNumber;
…
}
public class Address {
@Column(name
= "ADR_NUMBER")
private String houseNumber;
…
}
TAB_ADDRESS
ADR_STREET
ADR_NUMBER
…
public class Address {
@Column(name
= "ADR_HOUSE_NUMBER")
private String houseNumber;
…
}
public class Address {
@Column(name
= "ADR_NUMBER")
private String houseNumber;
…
}
TAB_ADDRESS
ADR_STREET
ADR_HOUSE_NUMBER
…
public class Address {
@Column(name
= "ADR_HOUSE_NUMBER")
private String houseNumber;
…
}
public class Address {
@Column(name
= "ADR_NUMBER")
private String houseNumber;
…
}
ALTER TABLE RENAME COLUMN ADR_NUMBER TO ADR_HOUSE_NUMBER
TAB_ADDRESS
ADR_STREET
ADR_NUMBER
…
public class Address {
@Column(name
= "ADR_NUMBER")
private String houseNumber;
…
}
public class Address {
@Column(name
= "ADR_NUMBER")
private String houseNumber;
…
}
TAB_ADDRESS
ADR_STREET
ADR_NUMBER
ADR_HOUSE_NUMBER
public class Address {
@Column(name
= "ADR_HOUSE_NUMBER")
private String houseNumber;
…
}
public class Address {
@Column(name
= "ADR_NUMBER")
private String houseNumber;
…
}
ALTER TABLE ADD COLUMN ADR_HOUSE_NUMBER VARCHAR(…);
CREATE TRIGGER TRG_ADR_NUMBER_TO_HOUSE_NUMBER …
…
TAB_ADDRESS
ADR_STREET
ADR_NUMBER
ADR_HOUSE_NUMBER
public class Address {
@Column(name
= "ADR_HOUSE_NUMBER")
private String houseNumber;
…
}
public class Address {
@Column(name
= "ADR_NUMBER")
private String houseNumber;
…
}
TAB_ADDRESS
ADR_STREET
ADR_NUMBER
ADR_HOUSE_NUMBER
public class Address {
@Column(name
= "ADR_HOUSE_NUMBER")
private String houseNumber;
…
}
public class Address {
@Column(name
= "ADR_HOUSE_NUMBER")
private String houseNumber;
…
}
DROP TRIGGER TRG_ADR_NUMBER_TO_HOUSE_NUMBER;
TAB_ADDRESS
ADR_STREET
ADR_HOUSE_NUMBER
public class Address {
@Column(name
= "ADR_HOUSE_NUMBER")
private String houseNumber;
…
}
public class Address {
@Column(name
= "ADR_HOUSE_NUMBER")
private String houseNumber;
…
}
DROP TRIGGER TRG_ADR_NUMBER_TO_HOUSE_NUMBER;
ALTER TABLE DROP COLUMN ADR_NUMBER;
API EXPAND CONTRACT
EXPAND
EXPAND
http://www.example.com/addresses/42
àLiefert Addresse
{
street: {
"name": "Poststraße",
"number": "1",
},
"city": "26122 Oldenburg"
}
EXPAND
http://www.example.com/addresses/42
Attribut hinzufügen
{
street: {
"name": "Poststraße",
"number": "1",
"additionalAdressLine": "2. Obergeschoss"
},
"city": "26122 Oldenburg"
}
EXPAND
http://www.example.com/addresses/42
Client erwartet
{
street: {
"name": "Poststraße",
"number": "1",
}...
}
Server schickt
{
street: {
"name": "Poststraße",
"number": "1",
"additionalAdressLine":
"2. Obergeschoss"
}...
}
Tolerant Reader Pattern
Tolerant gegenüber unbekannten Feldern
http://zalando.github.io/restful-api-guidelines
TOLERANT READER PATTERN
http://www.example.com/addresses/42
Attribut-Umbenennung
{
street: {
"name": "Poststraße",
"streetName": "Poststraße",
"number": "1",
"houseNumber": "1",
},
"city": "26122 Oldenburg"
}
TOLERANT READER PATTERN
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"
}
Tolerant Reader Pattern
Tolerant gegenüber unbekannten Feldern
Umgang mit x-extensible-enum
http://zalando.github.io/restful-api-guidelines
EXKURS X-EXTENSIBLE-ENUM
Beispiel
address_type:
type: string
x-extensible-enum:
- private
- business
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
OK, so soll sich
der Client verhalten.
Aber was ist mit dem Server?
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)
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
http://www.example.com/addresses/42
Client erwartet
{
street: {
"name": "Poststraße",
"number": "1",
}...
}
MAGNANIMOUS WRITER PATTERN
Server schickt
{
street: {
"name": "Poststraße",
"streetName": "Poststraße",
"number": "1",
"houseNumber": "1“
}...
}
http://tenderware.blogspot.de/2011/05/magnanimous-writer.html
http://www.example.com/addresses/42
Client erwartet
{
street: {
"streetName": "Poststraße",
"houseNumber": "1",
}...
}
MAGNANIMOUS WRITER PATTERN
Server schickt
{
street: {
"name": "Poststraße",
"streetName": "Poststraße",
"number": "1",
"houseNumber": "1“
}...
}
http://tenderware.blogspot.de/2011/05/magnanimous-writer.html
PUT http://www.example.com/addresses/42
Client schickt
{
street: {
"name": "Poststraße",
"number": "1",
}...
}
MAGNANIMOUS WRITER PATTERN
Server erwartet
http://tenderware.blogspot.de/2011/05/magnanimous-writer.html
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
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
MAGNANIMOUS WRITER UND JAVA
public String getNumber() {
return getHouseNumber();
}
public void setNumber(String number) {
setHouseNumber(number);
}
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?
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",
}
...
}
ABWÄRTSKOMPATIBILITÄT
http://www.example.com/addresses/42
àHerausforderungen: Zusammenführen von Attributen
{
street: {
...
"streetName": "Poststraße",
"houseNumber": "1",
"addressLine1": "Poststraße 1",
}
...
}
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"
}
ABWÄRTSKOMPATIBILITÄT
http://www.example.com/addresses/42
àHerausforderungen: Ebene von Attributen ändern
{
street: {
...
"addressLine1": "Poststraße 1"
}
"addressLine1": "Poststraße 1",
...
}
ABWÄRTSKOMPATIBILITÄT
http://www.example.com/addresses/42
àHerausforderungen: Ebene von Attributen ändern
{
...
"zipCode": "26122",
"cityName": "Oldenburg",
"location": {
"zipCode": "26122",
"cityName": "Oldenburg"
}
}
ABWÄRTSKOMPATIBILITÄT
public String getCity() {
return getZipCode() + ' ' + getCityName();
}
public void setCity(String city) {
setZipCode(city.substring(0, 5));
setCityName(city.substring(5).trim());
}
ABWÄRTSKOMPATIBILITÄT
public String getCity() {
return getZipCode() + ' ' + getCityName();
}
public void setCity(String city) {
setZipCode(city.substring(0, 5));
setCityName(city.substring(5).trim());
}
Bei jeder Modelländerung muss
eine Migrationsstrategie
einbezogen werden!
EXPAND
EXPAND
{
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
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
CONTRACT
Wie kann ich Attribute entfernen?
Don‘t ever break
your Client
Incompatible Change
vs. Breaking Change
http://zalando.github.io/restful-api-guidelines
S
e
r
v
i
c
e
B
a
c
k
e
n
d
API
Service
Frontend
Mobile
Frontend
A
n
o
t
h
e
r
S
e
r
v
i
c
e
B
a
c
k
e
n
d
B2B
Client
S
a
m
e
D
e
p
l
o
y
m
e
n
t
Same Company
Public
Client
WELCHE CLIENTS NUTZEN MICH?
WELCHE CLIENTS NUTZEN MICH?
API (PROVIDER CONTRACT)
CONSUMER CONTRACT
CONSUMER CONTRACT
CONSUMER-DRIVEN CONTRACT TEST
Consumer
Contract
Consumer Provider
Consumer
Tests
Provider
Tests
PIPELINE TO DEPLOY TO STAGE
Execute
Own
Provider
Tests
Generate
Consumer
Contract
Execute
Depending
Provider
Tests
Deploy
to
Stage
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!
BREAKING CHANGE VOM PROVIDER
Execute
Own
Provider
Tests
Generate
Consumer
Contract
Execute
Depending
Provider
Tests
Deploy
to
Stage
BREAKING CHANGE VOM CONSUMER
Execute
Own
Provider
Tests
Generate
Consumer
Contract
Execute
Depending
Provider
Tests
Deploy
to
Stage
Und wenn ich meine Consumer
nicht kenne?
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/addresses/42
Content-Type: application/json
àBisher nur abwärtskompatible Änderungen
INKOMPATIBLE ÄNDERUNG
http://www.example.com/addresses/42
Content-Type: application/vnd.de.openknowledge.v2+json
àVersionssprung
{
"addressLine1": "Poststraße 1",
"addressLine2": "",
"location": {
"zipCode": "26122",
"cityName": "Oldenburg"
}
}
ERMITTELN DER VERSION
Über URL-Pfad
/v2/addresses
Über Query-Parameter
/addresses?version=2
Ü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
INKOMPATIBLE ÄNDERUNG
Version 2.0 ist nur inkompatibel zu 1.0
Version 2.0 ist identisch zu 1.x
Mapping zwischen Versionen einfach
Änderung ist nicht anforderungsgetrieben
Update langfristig planbar
Wenn Änderung nicht abbildbar
è Neue Schnittstelle
VERSIONSMAPPING
Version 1.0
Domain
Version 2.0 Version 3.0
VERSIONSMAPPING
Version 1.0
Domain
Version 2.0 Version 3.0
API EXPAND CONTRACT – FAZIT
@ArneLimburg
Don‘t f*cking break the Client
Expand whenever you need
Contract carefully
FRAGEN
? ? ?
A N S P R E C H P A R T N E R
Kaiserliche Post, Poststraße 1, 26122 Oldenburg
www.openknowledge.de
OPENKNOWLEDGE
GmbH
Arne Limburg
Lead Architect
+49 151 108 22 942
arne.limburg@openknowledge.de
@ArneLimburg

Weitere ähnliche Inhalte

Mehr von OPEN KNOWLEDGE GmbH

Mehr von OPEN KNOWLEDGE GmbH (20)

Ready for the Future: Jakarta EE in Zeiten von Cloud Native & Co
Ready for the Future: Jakarta EE in Zeiten von Cloud Native & CoReady for the Future: Jakarta EE in Zeiten von Cloud Native & Co
Ready for the Future: Jakarta EE in Zeiten von Cloud Native & Co
 
Shared Data in verteilten Architekturen
Shared Data in verteilten ArchitekturenShared Data in verteilten Architekturen
Shared Data in verteilten Architekturen
 
Machine Learning mit TensorFlow.js
Machine Learning mit TensorFlow.jsMachine Learning mit TensorFlow.js
Machine Learning mit TensorFlow.js
 
KI und Architektur
KI und ArchitekturKI und Architektur
KI und Architektur
 
It's not Rocket Science: Neuronale Netze
It's not Rocket Science: Neuronale NetzeIt's not Rocket Science: Neuronale Netze
It's not Rocket Science: Neuronale Netze
 
Shared Data in verteilten Systemen
Shared Data in verteilten SystemenShared Data in verteilten Systemen
Shared Data in verteilten Systemen
 
Business-Mehrwert durch KI
Business-Mehrwert durch KIBusiness-Mehrwert durch KI
Business-Mehrwert durch KI
 
Mehr Sicherheit durch Automatisierung
Mehr Sicherheit durch AutomatisierungMehr Sicherheit durch Automatisierung
Mehr Sicherheit durch Automatisierung
 
API-Design, Microarchitecture und Testing
API-Design, Microarchitecture und TestingAPI-Design, Microarchitecture und Testing
API-Design, Microarchitecture und Testing
 
Supersonic Java für die Cloud: Quarkus
Supersonic Java für die Cloud: QuarkusSupersonic Java für die Cloud: Quarkus
Supersonic Java für die Cloud: Quarkus
 
Hilfe, ich will meinen Monolithen zurück!
Hilfe, ich will meinen Monolithen zurück!Hilfe, ich will meinen Monolithen zurück!
Hilfe, ich will meinen Monolithen zurück!
 
Das ist doch alles nur Frontend - Wer braucht da schon Architektur?
Das ist doch alles nur Frontend - Wer braucht da schon Architektur?Das ist doch alles nur Frontend - Wer braucht da schon Architektur?
Das ist doch alles nur Frontend - Wer braucht da schon Architektur?
 
Auf geht‘s in die Cloud: „Das kann doch nicht so schwer sein!“
Auf geht‘s in die Cloud: „Das kann doch nicht so schwer sein!“Auf geht‘s in die Cloud: „Das kann doch nicht so schwer sein!“
Auf geht‘s in die Cloud: „Das kann doch nicht so schwer sein!“
 
Das Product Goal oder "Ohne Ziele laufen eben alle in die Richtung, die ihnen...
Das Product Goal oder "Ohne Ziele laufen eben alle in die Richtung, die ihnen...Das Product Goal oder "Ohne Ziele laufen eben alle in die Richtung, die ihnen...
Das Product Goal oder "Ohne Ziele laufen eben alle in die Richtung, die ihnen...
 
Serverless Survival Guide
Serverless Survival GuideServerless Survival Guide
Serverless Survival Guide
 
Die Matrix: Enterprise-Architekturen jenseits von Microservices
Die Matrix: Enterprise-Architekturen jenseits von MicroservicesDie Matrix: Enterprise-Architekturen jenseits von Microservices
Die Matrix: Enterprise-Architekturen jenseits von Microservices
 
Auf gehts in die Cloud: „Das kann doch nicht so schwer sein!“
Auf gehts in die Cloud: „Das kann doch nicht so schwer sein!“Auf gehts in die Cloud: „Das kann doch nicht so schwer sein!“
Auf gehts in die Cloud: „Das kann doch nicht so schwer sein!“
 
Maschinen ohne Gewissen: wenn KI auf Ethik trifft
Maschinen ohne Gewissen: wenn KI auf Ethik trifftMaschinen ohne Gewissen: wenn KI auf Ethik trifft
Maschinen ohne Gewissen: wenn KI auf Ethik trifft
 
Zukunftssichere Architekturen mit Microservices
Zukunftssichere Architekturen mit MicroservicesZukunftssichere Architekturen mit Microservices
Zukunftssichere Architekturen mit Microservices
 
Modern Web: Trends der Webentwicklung
Modern Web: Trends der WebentwicklungModern Web: Trends der Webentwicklung
Modern Web: Trends der Webentwicklung
 

API Expand Contract