The document discusses versioning REST APIs in a backwards compatible way using VeRST (Versioned Representational State Transfer). It describes how attributes can be renamed, moved between classes, combined, split apart, and deprecated across versions while maintaining compatibility. Transformations are defined through annotations on Java classes and properties. Complex changes can be handled through custom Java code providers. The approach aims to allow incompatible changes while still supporting older API versions.
5. VeRST | Arne Limburg
Abwärtskompatible Weiterentwicklung
http://www.example.com/v1/addresses/42
Abwärtskompatible Änderungen: Umbenennen durch Kopieren
{
street: {
"name": "Poststraße",
"streetName": "Poststraße",
"number": "1",
"houseNumber": "1",
}
"city": "26122 Oldenburg"
}
• Server muss mit beiden Varianten
als Parameter umgehen können
• Server muss beide Varianten als
Antwort liefern können
Tolerant Reader Pattern
6. VeRST | Arne Limburg
Abwärtskompatible Weiterentwicklung
http://www.example.com/v1/addresses/42
Abwärtskompatible Änderungen: Umbenennen durch Kopieren
{
street: {
"name": "Poststraße",
"streetName": "Poststraße",
"number": "1",
"houseNumber": "1",
}
"city": "26122 Oldenburg"
}
• Server muss mit beiden Varianten
als Parameter umgehen können
• Server muss beide Varianten als
Antwort liefern können
Tolerant Reader Pattern
„Be conservative in what you do, be liberal in what you
expect.“
Postels Law (Jon Postel)
7. VeRST | Arne Limburg
Abwärtskompatible Weiterentwicklung
http://www.example.com/v1/addresses/42
Abwärtskompatible Änderungen: Umbenennen durch Kopieren
{
street: {
"name": "Poststraße",
"streetName": "Poststraße",
"number": "1",
"houseNumber": "1",
}
"city": "26122 Oldenburg"
}
• Server muss mit beiden Varianten
als Parameter umgehen können
• Server muss beide Varianten als
Antwort liefern können
Tolerant Reader Pattern
Idee: Automatisierung durch Framework VeRST
8. VeRST | Arne Limburg
Abwärtskompatible Weiterentwicklung
public class Address {
private Street street;
private String city;
}
public class Street {
private String name;
private String number;
}
9. VeRST | Arne Limburg
Transformation durch Annotations
public class Address {
private Street street;
private String city;
}
public class Street {
@Deprecated
private String name;
@MovedFrom("name")
private String streetName;
@Deprecated
private String number;
@MovedFrom("number")
private String houseNumber;
}
10. VeRST | Arne Limburg
Transformation durch Annotations
public class Address {
private Street street;
private String city;
}
public class Street {
@Deprecated
private String name;
@MovedFrom("name")
private String streetName;
@Deprecated
private String number;
@MovedFrom("number")
private String houseNumber;
}
11. VeRST | Arne Limburg
Herausforderungen
http://www.example.com/v1/addresses/42
Zusammenführen und Teilen von Attributen
{
street: {
...
"streetName": "Poststraße",
"houseNumber": "1",
"addressLine1": "Poststraße 1",
}
...
}
12. VeRST | Arne Limburg
Zusammenführen von Attributen
http://www.example.com/v1/addresses/42
Herausforderungen: Zusammenführen und Teilen von Attributen
{
street: {
...
"streetName": "Poststraße",
"houseNumber": "1",
"addressLine1": "Poststraße 1",
}
...
}
13. VeRST | Arne Limburg
Teilen von Attributen
http://www.example.com/v1/addresses/42
Herausforderungen: Zusammenführen und Teilen von Attributen
{
street: {
...
"addressLine1": "Poststraße 1",
}
"city": "26122 Oldenburg",
"zipCode": "26122",
"cityName": "Oldenburg"
}
14. VeRST | Arne Limburg
Zusammenführen und Teilen von Attributen
http://www.example.com/v1/addresses/42
Herausforderungen: Zusammenführen und Teilen von Attributen
{
street: {
...
"addressLine1": "Poststraße 1",
}
"city": "26122 Oldenburg",
"zipCode": "26122",
"cityName": "Oldenburg"
}
Idee: Komplexe Transformationen über Java-Code
15. VeRST | Arne Limburg
Transformation über Java-Code
public class Address {
private Street street;
@Removed(CityProvider.class)
private String city;
@Added(CitySplitProvider.class)
private String zipCode;
@Added(CitySplitProvider.class)
private String cityName;
}
public class Street {
...
@Removed(StreetNamePr...class)
private String streetName;
@Removed(HouseNumberP...class)
private String houseNumber;
@Added(AddressLinePro...class)
private String addressLine1;
@Added(defaultValue = "")
private String addressLine2;
}
16. VeRST | Arne Limburg
Transformation über Java-Code
public class CitySplitProvider implements Provider<String> {
public String get(VersionContext versionContext) {
Address address = versionContext.getParent(Address.class);
String city = address.getCity();
if (versionContext.getPropertyName().equals("zipCode")) {
return city.substring(0, 5);
} else if (versionContext.getPropertyName().equals("cityName")){
return city.substring(6).trim();
} else {
throw new IllegalArgumentException(...);
}}}
17. VeRST | Arne Limburg
Ebene von Attributen ändern
http://www.example.com/v1/addresses/42
Herausforderungen: Ebene von Attributen ändern
{
street: {
...
"addressLine1": "Poststraße 1"
}
"addressLine1": "Poststraße 1",
...
}
18. VeRST | Arne Limburg
Ebene von Attributen ändern
http://www.example.com/v1/addresses/42
Herausforderungen: Ebene von Attributen ändern
{
...
"zipCode": "26122",
"cityName": "Oldenburg",
"location": {
"zipCode": "26122",
"cityName": "Oldenburg"
}
}
19. VeRST | Arne Limburg
Ebene von Attributen ändern
public class Address {
private Street street;
@MovedFrom(
"street/addressLine1")
private String addressLine1;
...
private City location;
}
public class City {
@MovedFrom("../zipCode")
private String zipCode;
@MovedFrom("../cityName")
private String cityName;
}
20. VeRST | Arne Limburg
Default-Werte für Attribute
public class Address {
private Street street;
@MovedFrom(
"street/addressLine1")
private String addressLine1;
@Added(defaultValue = " ")
private String addressLine2;
...
private City location;
}
public class City {
@MovedFrom("../zipCode")
private String zipCode;
@MovedFrom("../cityName")
private String cityName;
}
21. VeRST | Arne Limburg
Default-Werte für Attribute
public class Address {
private Street street;
@MovedFrom(
"street/addressLine1")
private String addressLine1;
@Added(defaultValue = " ")
private String addressLine2;
...
private City location;
}
public class City {
@MovedFrom("../zipCode")
private String zipCode;
@MovedFrom("../cityName")
private String cityName;
}
26. VeRST | Arne Limburg
Version über URL
@Path("{version}/addresses")
public class AddressResource {
@GET
@Path("{id}")
public Address getAddress(@PathParam("id") String id) {
...
}
}
27. VeRST | Arne Limburg
Version über URL
@Path("{version}/addresses")
public class AddressResource {
@GET
@Path("{id}")
public Address getAddress(@PathParam("id") String id) {
...
}
}
28. VeRST | Arne Limburg
Versionierung über Annotations
@SupportedVersion(
version = "v2"
previous = AddressV1.class)
public class Address {
private Street street;
@MovedFrom("...")
private String addressLine1;
...
private City location;
}
public class City {
@MovedFrom("../zipCode")
private String zipCode;
@MovedFrom("../cityName")
private String cityName;
}
29. VeRST | Arne Limburg
Versionierung über Annotations
@SupportedVersion(
version = "v2"
previous = AddressV1.class)
public class Address {
private Street street;
@MovedFrom("...")
private String addressLine1;
...
private City location;
}
public class City {
@MovedFrom("../zipCode")
private String zipCode;
@MovedFrom("../cityName")
private String cityName;
}