Nicht erst seit dem Hype um Microservices ist Schnittstellendesign ein essenzieller Bestandteil von Softwareentwicklung. Doch jede noch so gut definierte Schnittstelle kann an einen Punkt kommen, an dem sie weiterentwickelt werden muss; sei es nur, weil sich die Anforderungen geändert haben. Kommt man an diesen Punkt, stellt sich die Frage: Muss ich meine Schnittstelle versionieren? Wenn ja, wie gehe ich vor? Wie müssen sich die Clients der Schnittstelle verhalten, um nicht plötzlich (nach einem neuen Release des Servers) eine böse Überraschung zu erleben? Die Weiterentwicklung einer Schnittstelle wird leider initial häufig nicht bedacht. Hoher Wartungsaufwand für die Bedienung alter und neuer Schnittstellen sind die Folge. Wie kann ich das verhindern? Wie muss ich bei der Weiterentwicklung vorgehen, um alte Clients nicht inkompatibel werden zu lassen und dennoch nicht in der Versionierungshölle zu landen? Diese und weitere Fragen werden in dieser Session beantwortet. Dabei werden die Konzepte nicht nur in der Theorie beleuchtet. Anhand von Beispielen zeige ich, wie Abwärtskompatibilität in der Praxis realisiert werden kann, ohne sich im Support alter Versionen zu verlieren.
31. Tolerant Reader Pattern
Tolerant gegenüber unbekannten Feldern
Umgang mit x-extensible-enum
Tolerant gegenüber unbekannten Statuscodes
http://zalando.github.io/restful-api-guidelines
HTTP Status 301 folgen
37. Und was ist, wenn der Client kein
Tolerant Reader ist?
38. 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
39. OK, so soll sich
der Client verhalten.
Aber was ist mit dem Server?
40. 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)
41. 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
54. MERGE PATCH UND NULL VALUES
public class Street {
private String streetName;
private String streetNumber;
public void setName(String name) { setStreetName(...
public void setNumber(String number) { setStreetNum...
}
Wird mit null aufgerufen
Wird gar nicht aufgerufen
55. MERGE PATCH UND NULL VALUES
public class Street {
private String streetName; // = null
private String streetNumber; // = null
public void setName(String name) { setStreetName(...
public void setNumber(String number) { setStreetNum...
}
56. MERGE PATCH UND NULL VALUES
public class Street {
private String streetName; // = null
private String streetNumber; // = null
public void setName(String name) { setStreetName(...
public void setNumber(String number) { setStreetNum...
}
Simple Solution:
Don‘t use PATCH at all
57. MERGE PATCH UND NULL VALUES
public class Street {
private String streetName; // = null
private String streetNumber; // = null
public void setName(String name) { setStreetName(...
public void setNumber(String number) { setStreetNum...
}
Advanced Solution:
Use initial values
58. MERGE PATCH UND NULL VALUES
public class Street {
private String streetName = "<initial value>";
private String streetNumber = "<initial value>";
public void setName(String name) { setStreetName(...
public void setNumber(String number) { setStreetNum...
}
59. MERGE PATCH UND NULL VALUES
public class Street {
private String streetName = "<initial value>";
private String streetNumber = "<initial value>";
public void setName(String name) { setStreetName(...
public void setNumber(String number) { setStreetNum...
}
Wird mit null aufgerufen
Wird gar nicht aufgerufen
60. MERGE PATCH UND NULL VALUES
public class Street {
private String streetName; // = null
private String streetNumber = "<initial value>";
public void setName(String name) { setStreetName(...
public void setNumber(String number) { setStreetNum...
}
Wird mit null aufgerufen
Wird gar nicht aufgerufen
69. Was ist daran jetzt besser als an
einer Mapping-Schicht?
70. Migrations-Strategie für jede Attributänderung
Code für Migration sehr nah an der Schnittstelle
Migrations-Regeln innerhalb des Objekts
Code unabhängig
87. Version 2.0
ist nur inkompatibel zu 1.0!
Version 2.0 ist identisch zu 1.x!
Das erleichtert das Mapping
zwischen den Versionen!
88. Ein solcher Versionssprung ist
nicht anforderungsgetrieben,
sondern viel besser und
langfristiger planbar
89. Wenn eine neue Version
nicht auf die alte abbildbar ist,
ist es keine neue Version,
sondern eine neue Schnittstelle!
90. • Ü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