Advertisement

API Expand Contract

OPEN KNOWLEDGE GmbH
Feb. 14, 2023
Advertisement

More Related Content

More from OPEN KNOWLEDGE GmbH(20)

Advertisement

API Expand Contract

  1. API EXPAND CONTRACT @ArneLimburg
  2. ÜBER MICH Arne Limburg – Lead Architect @ArneLimburg • APIs • Microservices • Domain Driven Design • Architektur • Coaching • Technologie (Java EE / Jakarta EE)
  3. 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
  4. EXPAND & CONTRACT
  5. TAB_ADDRESS ADR_STREET ADR_NUMBER … ALTER TABLE RENAME COLUMN ADR_NUMBER TO ADR_HOUSE_NUMBER
  6. 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
  7. 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
  8. 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
  9. 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
  10. UNTERBRECHUNGSFREI?
  11. 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; … }
  12. 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; … }
  13. 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
  14. 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; … }
  15. 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 … …
  16. 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; … }
  17. 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;
  18. 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;
  19. API EXPAND CONTRACT
  20. EXPAND
  21. EXPAND http://www.example.com/addresses/42 àLiefert Addresse { street: { "name": "Poststraße", "number": "1", }, "city": "26122 Oldenburg" }
  22. EXPAND http://www.example.com/addresses/42 Attribut hinzufügen { street: { "name": "Poststraße", "number": "1", "additionalAdressLine": "2. Obergeschoss" }, "city": "26122 Oldenburg" }
  23. 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" }... }
  24. Tolerant Reader Pattern Tolerant gegenüber unbekannten Feldern http://zalando.github.io/restful-api-guidelines
  25. 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" }
  26. 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" }
  27. Tolerant Reader Pattern Tolerant gegenüber unbekannten Feldern Umgang mit x-extensible-enum http://zalando.github.io/restful-api-guidelines
  28. EXKURS X-EXTENSIBLE-ENUM Beispiel address_type: type: string x-extensible-enum: - private - business
  29. 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
  30. OK, so soll sich der Client verhalten. Aber was ist mit dem Server?
  31. 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)
  32. 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
  33. 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
  34. 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
  35. 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
  36. 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
  37. 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
  38. MAGNANIMOUS WRITER UND JAVA public String getNumber() { return getHouseNumber(); } public void setNumber(String number) { setHouseNumber(number); }
  39. 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?
  40. 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", } ... }
  41. ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 àHerausforderungen: Zusammenführen von Attributen { street: { ... "streetName": "Poststraße", "houseNumber": "1", "addressLine1": "Poststraße 1", } ... }
  42. 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" }
  43. ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 àHerausforderungen: Ebene von Attributen ändern { street: { ... "addressLine1": "Poststraße 1" } "addressLine1": "Poststraße 1", ... }
  44. ABWÄRTSKOMPATIBILITÄT http://www.example.com/addresses/42 àHerausforderungen: Ebene von Attributen ändern { ... "zipCode": "26122", "cityName": "Oldenburg", "location": { "zipCode": "26122", "cityName": "Oldenburg" } }
  45. ABWÄRTSKOMPATIBILITÄT public String getCity() { return getZipCode() + ' ' + getCityName(); } public void setCity(String city) { setZipCode(city.substring(0, 5)); setCityName(city.substring(5).trim()); }
  46. 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!
  47. EXPAND
  48. 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
  49. 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
  50. CONTRACT
  51. Wie kann ich Attribute entfernen?
  52. Don‘t ever break your Client
  53. Incompatible Change vs. Breaking Change http://zalando.github.io/restful-api-guidelines
  54. 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?
  55. WELCHE CLIENTS NUTZEN MICH?
  56. API (PROVIDER CONTRACT)
  57. CONSUMER CONTRACT
  58. CONSUMER CONTRACT
  59. CONSUMER-DRIVEN CONTRACT TEST Consumer Contract Consumer Provider Consumer Tests Provider Tests
  60. PIPELINE TO DEPLOY TO STAGE Execute Own Provider Tests Generate Consumer Contract Execute Depending Provider Tests Deploy to Stage
  61. 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!
  62. BREAKING CHANGE VOM PROVIDER Execute Own Provider Tests Generate Consumer Contract Execute Depending Provider Tests Deploy to Stage
  63. BREAKING CHANGE VOM CONSUMER Execute Own Provider Tests Generate Consumer Contract Execute Depending Provider Tests Deploy to Stage
  64. Und wenn ich meine Consumer nicht kenne?
  65. 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
  66. 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" } }
  67. 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
  68. INKOMPATIBLE ÄNDERUNG
  69. Version 2.0 ist nur inkompatibel zu 1.0 Version 2.0 ist identisch zu 1.x Mapping zwischen Versionen einfach
  70. Änderung ist nicht anforderungsgetrieben Update langfristig planbar
  71. Wenn Änderung nicht abbildbar è Neue Schnittstelle
  72. VERSIONSMAPPING Version 1.0 Domain Version 2.0 Version 3.0
  73. VERSIONSMAPPING Version 1.0 Domain Version 2.0 Version 3.0
  74. API EXPAND CONTRACT – FAZIT @ArneLimburg Don‘t f*cking break the Client Expand whenever you need Contract carefully
  75. FRAGEN ? ? ?
  76. 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
Advertisement