简体   繁体   中英

Versioning of input in Java API

I have a Spring Boot API which takes JSON as the input and uses the data to populate an XML which is sent to another application.

I'm currently looking at versioning for this. One approach I'm taking is to add either URI or header based versioning. I'll most likely go for the header based option by including the version in the Accept header.

I'm also looking into options for versioning the input data itself. The input JSON has changed quite significantly recently and this has caused problems where any updates have had to be coordinated with updates to the client applications. If possible I want to include some form of versioning so API updates can be released without need to coordinate with client updates.

An example of changes include the below where the JSON structure was changed from:

{
  "customer": {
    "dateOfBirth": "01/01/1970",
    "occupation": "TCH",
    "contractDetails": {
        "startDate": "08/12/2022"
    }
}

to:

{
  "customer": {
    "personalDetails: {
      "dateOfBirth": "01/01/1970",
      "occupation": "TCH"
    },
    "contractDetails": {
        "startDate": "08/12/2022"
    }
}

In my application I had a Customer model which looked like this:

@Data
@AllArgsConstructor(access=AccessLevel.PACKAGE)
@NoArgsConstructor(access=AccessLevel.PACKAGE)
@Builder(toBuilder=true)
public class Customer {
  @NotEmpty 
  private String dateOfBirth;

  @NotNull
  @Pattern(regexp="^[A-Z]{3}", message=INVALID_CODE)
  private String occupation;

  @Valid @NotNull private ContractDetails contractDetails;
}

Has now changed to:

@Data
@AllArgsConstructor(access=AccessLevel.PACKAGE)
@NoArgsConstructor(access=AccessLevel.PACKAGE)
@Builder(toBuilder=true)
public class Customer {
  @Valid @NotNull private PersonalDetails personalDetails;
  @Valid @NotNull private ContractDetails contractDetails;
}


@SuperBuilder(toBuilder=true)
@Data
@AllArgsConstructor(access=AccessLevel.PACKAGE)
@NoArgsConstructor(access=AccessLevel.PACKAGE)
public class PersonalDetails {
  @NotEmpty 
  private String dateOfBirth;

  @NotNull
  @Pattern(regexp="^[A-Z]{3}", message=INVALID_CODE)
  private String occupation;
}

Is there any way I can identify variables or classes with some type of versioning so one client might continue to use the old structure whislt anothe client might use the new structure? Without some means of identifying this the API could quickly accumulate a lot of duplicate code and it may be confusing for anyone to enhance/debug. Eventually I'd like to include some process for identifying versions that are no longer in use and depricate them.

There are many methods to version input data in your Spring Boot API. Some choices:

Using a version field in the JSON payload: You might send the API a version field. This field would reflect the client's payload structure version. The API might then utilise this field to parse and process the payload.

Various endpoints for distinct API versions: You may use different endpoints for different API versions. For instance, you may have /api/v1/customer and /api/v2/customer, where v1 expects the old payload structure and v2 expects the new.

Content negotiation: You may use content negotiation to let customers choose which API version to use. A version parameter in the Accept header might achieve this. "Accept: application/vnd.myapi.v1+json," for instance.

Various package names: You might use different package names for different model class versions. For instance, you may have com.myapi.model.v1.Customer and v2.Customer. This would let you have various class versions without naming problems.

Jackson's @JsonTypeInfo and @JsonSubTypes annotations to define class versions in the class specification. The API will utilise the right class version if you indicate the class version.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM