In this article of REST with Spring Series, we will discuss versioning a REST API.
Introduction
Evolving a REST API is a difficult and complex task. When REST API reached a point where it’s difficult to expand beyond the original intent, it’s time to consider the next version. In this post, we will walk through the different options of versioning a REST API. While going to next iteration for your REST API, we should consider following points
- Is the next version/ iteration will be a whole number (e.g. v1 to v2) or an increment to existing iteration (e.g. v1.1 from v1.0).
[pullquote align=”normal”]URI design is the most prominent part of a REST API and, therefore, a potentially long-term commitment towards the users of that API. [/pullquote]
1. When to Version REST API
As mentioned above, REST API design is a long-term commitment towards the users of that API, REST API should only be up-versioned when significant or groundbreaking changes made in the API. Here is the list of some common points when we
- Remove API part.
- Architectural changes to the API design.
- Changes in the response format.
As a thumb rule, a big number change(e.g. v1 to v2) shows groundbreaking changes or significant milestone in the REST API design and features. This also shows REST API consumer significant changes. All minor changes like new endpoints etc. are known as non-breaking changes. Use minor version increment (v1.0 to v1.1) to show these changes in the API.
2. REST API Versioning Options
On a high level, there are 4 possible options when versioning a REST API. We are covering all these options with their pros and cons.
2.1 URI Versioning
This is the most commonly used and straightforward approach while versioning a REST API. Let’s take an example of following resources – products and customers.
https://hostname/v1/products
https://hostname/v1/customers
Let’s assume that we are introducing groundbreaking changes to the REST API, to represent this, we introduce a new version to our REST API resource structure
https://hostname/v2/products
https://hostname/v2/customers
The version need not be numeric. Let’s look at some pros and cons of this approach.
Pros:
- Enable version discovery.
- Readability and dev friendly.
- Ability to version specific resource branches.
Cons:
- Violate the principle that a URI should refer to a unique resource or structure only.
- New version breaks existing hyper-links.
- HTTP Caching is also a major concern.
- New versions change resource name and location.
2.2 Versioning using Accept Header
Content negotiation using HTTP Accept header can be used for the REST API versioning. To handle versioning, REST API would use MIME type to determine the API versioning.
Accept: application/vnd.javadevjournal.v2+json
Accept: application/vnd.javadevjournal+json;version=1.0
it is important to understand here is that the client makes no assumptions about the structure of the response beyond what it define in the media type.
############## GET Request for Products ##############
GET /products/228781 HTTP/1.1
Accept: application/vnd.javadevjournal.v1+json
############## Response ##############
HTTP/1.1 200 OK
Content-Type: application/vnd.javadevjournal.v1+json
{
"product": {
"code": "228781",
"name": "Running shoes",
"description": "one of the best running shoes"
}
}
Let’s look at some pros and cons of this approach.
Pros:
- Clean URI structure (no version information in the URI structure)
Cons:
- Complex API structure since underlying system is responsible for figuring out which version of a resource to send.
- Not enough semantic information. Information is not clear and hidden with use of Accept header.
- Accept headers are hard to test.
2.3 Versioning using Custom Header.
Another alternative is to use a custom header for handling API versioning. This approach is like the one described in section 2.2.
Accept-version: v1
Accept-version: v2
2.4 Versioning using URI parameter.
This is the least used method to version your REST API. Append version as a query parameter.
http://host/shopping?version=2.0
http://host/catalog/titles/series/70023522?v=1.5
3. REST API Versioning Best Practices
The idea of versioning with a RESTful API is far from reaching a universal standard. As a thumb rule, we can follow certain guidelines while versioning our REST API.
- REST API versioning depends on the REST API design. With good API design, we rarely need major versions unless changing the behavior of the whole API at once.
- The URI design should have less natural constraints and it should be preserved over time.
- Use aliasing while versioning your REST API. For example
https://javadevjournal.com/v3.0/products/228781 https://javadevjournal.com/v3/products/228781
should be aliases
- If REST API client tries to use old API, the system should return HTTP 410 status code.
[pullquote align=”normal”]Recommendation is to not use API versions in resource URIs, however, using a version number in the URL should be not a bad practice when the underlying implementation changes and being used by all major players (e.g. Google, GitHub etc.) [/pullquote]
4. Examples
We discussed when we need API Versioning in Section 1, let’s take examples to understand it more clearly.
4.1 Adding Additional information to Resource
the Resource representation in REST API should not be tightly bound to a client and should be as generic as possible. The client should only consume require information and ignore information which is relevant to the client. This help to expand REST API resource representation without breaking existing clients. Let’s take an example of product resource.
{
"product":{
"code":"228781",
"name":"Running shoes",
"description":"one of the best running shoes",
"price":"100.00"
}
}
Let’s assume that we may want to introduce “promotional price” as an additional information in the REST response needed by some REST client
{
"product":{
"code":"228781",
"name":"Running shoes",
"description":"one of the best running shoes",
"price":"100.00",
"promotional_price":"90.00"
}
}
This change will not break existing clients, they can continue to ignore “promotional_price” information.
4.2 Changing Existing Representation/Semantic Changes
Redesigning, changing or removing the representation is known as breaking changes and require REST client to change the implementation. To handle such changes, we have the options to use HTTP header as part of the content negotiation or use API versioning if API includes major changes (content and semantics). Let’s take an example where we like to change the product code to product SKU in the API
############## GET Request for Products ##############
GET /products/228781 HTTP/1.1
Accept: application/vnd.javadevjournal.v2+json
############## Response ##############
HTTP/1.1 200 OK
Content-Type: application/vnd.javadevjournal.v2+json
{
"product": {
"sku": "228781",
"name": "Running shoes",
"description": "one of the best running shoes",
"price" : "100.00",
"promotional_price":"90.00"
}
}
Summary
The idea of versioning with a RESTful API is far from reaching a universal standard. In this article, we tried to cover a complex topic of versioning a REST API. We discussed 4 different approaches to consider while versioning the REST API. Take in to account your development team and customers while determining the best approach for versioning.