Versioning REST APIs

Introduction

 
The only thing that is constant in software engineering is: Change! Like it or Not!
 
This reality often takes a pivotal role while designing software. The design of REST APIs are of no exception. The moment your REST APIs are out in public, clients start consuming those based on the interface contract of that API. But more often than not a new requirement of enhancement might introduce breaking changes into these contracts. How do we handle this? How would the client still work with the APIs provided without having to immediately re-develop their consumption? The answer lies in the designing phase of the REST APIs where the API versioning is considered.
 
In this article, I shall be talking about different ways in which a REST API endpoint could be versioned by mentioning the Pros & Cons of each one of them. So, let’s get started versioning in the URI!
 
Example 
  1. // Uri for the API which GET data for a specific ‘employee’ with version in uri path  
  2.   
  3. https://localhost:44323/api/v1/Employees/2  
Plus
 
It's easy to comprehend both from the consumer as well as from the developer perspective.
 
Minus
 
It could turn out to be slightly annoying and error-prone to track and consume the different versions with URI path fragment
 

Versioning in the Query String

 
Example 
  1. // Uri for the API which GET data for a specific ‘employee’ with version in query string  
  2.   
  3. https://localhost:44323/api/Employees/2?v=1.0  
Plus
 
Easy to comprehend by the consumer. The default version can be accommodated with omission of the query param.
 
Minus
 
Error-prone if the explicit version is not mentioned in the query param.
 

Versioning in the Custom Header

 
Example 
  1. GET /api/Employees/2 HTTP/1.1  
  2. Host: localhost:44323  
  3. Content-Type: application/json  
  4. Accept-Version: 2.0  
Plus
 
Versioning strategy is separated out from the URI path.
 
Minus
 
No easily discoverable as with the URI path. Requires slightly higher sophistication (e.g. interceptors etc.) in development and testing the versions.
 

Versioning in the Accept Header

 
Example 1
  1. GET /api/Employees/2 HTTP/1.1  
  2. Host: localhost:44323  
  3. Content-Type: application/json  
  4. Accept: application/json;version=2.0  
Example 2 
  1. GET /api/Employees/2 HTTP/1.1  
  2. Host: localhost:44323  
  3. Content-Type: application/vnd.example.v2+json  
  4. Accept: application/vnd.example.v2+json  
Plus 
 
No need to intercept and use custom headers.
 
Minus 
 
Much lesser accessible than URI path versioning and custom header comparatively. It also becomes difficult to test and explore the different versions of the API using a browser.
 

Summary 

 
Web API designing should always revolve around what is convenient for consumers. Versioning an API thus becomes a crucial part of the design. Once the customers start consuming an API with a given contract, the only way to accommodate the change to it is through versioning of the APIs.
 
The simple URI path versioning provides an easy way to design versioning. The content negotiation requires a more sophisticated development and testing approach. For a long-running enterprise-level Web API, the comparatively higher investment on a more robust mechanism with content negotiation could turn out to be beneficial.
 
How do you version your APIs? Do you follow some other design strategies that you found useful? Please let me know in the comment section!