This article explains how to use Spring Boot built-in API versioning feature to expose different versions of REST endpoints. This is one of the most interesting updates introduced with Spring Boot 4. API versioning can be implemented using Spring Web’s standard REST API capabilities. If you’re interested in this approach, check out my somewhat outdated article on the subject here.

Interestingly, the Micronaut framework also provides built-in API versioning. You can read more about it in the framework’s documentation here.

Source Code

Feel free to use my source code if you’d like to try it out yourself. To do that, you must clone my sample GitHub repository. Then you should only follow my instructions.

Introduction

The Spring Boot example application discussed in this article features two versions of the data model returned by the API. Below is the basic structure of the Person object, which is shared across all API versions.

The scenario assumes that we choose the option that returns the same age for a person in two different ways. This is a somewhat pessimistic version, but it is the one we want to examine. In the first method, we return JSON containing the birthdate. In the second method, we return the age field. Below is the PersonOld object implementing the first approach.

Here, we see the PersonCurrent object, which contains the age field instead of the previously used birthDate.

Design API for Versioning with Spring Boot

API Methods

Now we can design an API that supports different object versions on one hand and two distinct versioning methods on the other. In the first method, we will use the HTTP header, and in the second, the request path. For clarity, below is a table of REST API methods for HTTP header-based versioning.

Method type Method path Description
POST /persons Add a new person, v1.2 for PersonCurrent, v1.[0-1] for PersonOld
PUT /persons/{id} Update a person, v1.2 for PersonCurrent, v1.1 for PersonOld
DELETE /persons/{id} Delete a person
GET /persons/{id} Find a person by ID, v1.2 for PersonCurrent

Here, in turn, is a table for versioning based on the request path.

Method type Method path Description
POST /persons/v1.0, /persons/v1.1 Add a new person (PersonOld)
POST /persons/v1.2 Add a new person (PersonCurrent)
PUT /persons/v1.0 Update a person – v1.0 deprecated
PUT /persons/v1.1/{id} Update a person with ID (PersonOld)
PUT /persons/v1.2/{id} Update a person with ID (PersonCurrent)
DELETE /persons/v1.0, /persons/v1.1, … Delete a person
GET /persons/v1.0/{id}, /persons/v1.1 Find a person by ID, v1.0[1] for PersonOld
GET /persons/v1.2/{id} Find a person by ID, v1.2 for PersonCurrent

Spring Boot Implementation

To enable the built-in API versioning mechanism in Spring Web MVC, use spring.mvc.apiversion.* properties. The following configuration defines both of the API versioning methods mentioned above. In the header-based method, set its name. The header name used for testing purposes is api-version. In request path versioning, we must set the index of the path segment dedicated to the field with version. In our case, it is 1, because the version is read from the segment after the 0th element in the path, which is /persons. Please note that the two types of versions are only activated for testing purposes. Typically, you should select and use one API versioning method.

Let’s continue by implementing individual API controllers. We use the @RestController approach for each versioning method. Now, in each annotation that specifies an HTTP method, we can include the version field. The mechanism maps the api-version header to the version field in the annotation. We can use syntax like v1.0+ to specify a version higher than v1.0.

Then, we can implement a similar approach, but this time based on the request path. Here’s our @RestController.

Let’s start our application using the command below.

We can test the REST endpoints of both controllers using the following curl commands. Below are the calls and the expected results.

Testing API versioning with Spring Boot REST client

Importantly, Spring also offers support for versioning on the HTTP client side. This applies to both RestClient and WebClient, as well as their testing implementations. I don’t know if you’ve had a chance to use RestTestClient in your tests yet. After initializing the client instance, set the versioning method using apiVersionInserter. Then, when calling a given HTTP method, you can set the version number by calling apiVersion(...) with the version number as an argument. Below is a class that tests versioning using an HTTP header.

And here are similar tests, but this time for versioning based on the request path.

Here are my test results.

OpenAPI for Spring Boot API versioning

I also tried to check what support for API versioning looks like on the Springdoc side. This project provides an OpenAPI implementation for Spring MVC. For Spring Boot 4, we must use at least 3.0.0 version of Springdoc.

My goal was to divide the API into groups based on version for a path segment approach. Unfortunately, attempting this type of implementation results in an HTTP 400 response for both the /v3/api-docs and /swagger-ui.html URLs. That’s why I created an issue in Springdoc GitHub repository here. Once they fixed problems or eventually explain what I should improve in my implementation, I’ll update the article.

Conclusion

Built-in API versioning support is one of the main features in Spring Boot 4. It works very smoothly. Importantly, API versioning is supported on both the server and client sides. We can also easily integrate it in JUnit tests with RestTestClient and WebTestClient. This article demonstrates Spring MVC implementation, but you can also use the built-in versioning API for Spring Boot applications based on the reactive WebFlux stack.

Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
Leave A Reply