Versioning REST API !

Introduce new features with ease.


6 min read

It is highly unlikely that a web API will remain static. As business requirements change new collections of resources may be added, the relationships between resources might change, and the structure of the data in resources might be amended. While updating a web API to handle new or differing requirements is a relatively straightforward process, you must consider the effects that such changes will have on client applications consuming the web API. The issue is that although the developer designing and implementing a web API has full control over that API, the developer does not have the same degree of control over client applications, which may be built by third-party organizations operating remotely. The primary imperative is to enable existing client applications to continue functioning unchanged while allowing new client applications to take advantage of new features and resources.

Versioning enables a web API to indicate the features and resources that it exposes, and a client application can submit requests that are directed to a specific version of a feature or resource. The following sections describe several different approaches, each of which has its own benefits and trade-offs.

No versioning

This is the simplest approach, and may be acceptable for some internal APIs. Significant changes could be represented as new resources or new links. Adding content to existing resources might not present a breaking change as client applications that are not expecting to see this content will ignore it.

For example, a request to the URI should return the details of a single customer containing id, name, and address fields expected by the client application:

{"id":3,"name":"Coderhop LLC","address":"109 TT street 98053,NYC"}

If the DateCreated field is added to the schema of the customer resource, then the response would look like this:

{"id":3,"name":"Coderhop LLC","address":"109 TT street 98053,NYC","dateCreated":"2014-09-04T12:11:38.0376089Z"}

Existing client applications might continue functioning correctly if they are capable of ignoring unrecognized fields, while new client applications can be designed to handle this new field. However, if more radical changes to the schema of resources occur (such as removing or renaming fields) or the relationships between resources change then these may constitute breaking changes that prevent existing client applications from functioning correctly. In these situations, you should consider one of the following approaches.

URI versioning

Each time you modify the web API or change the schema of resources, you add a version number to the URI for each resource. The previously existing URIs should continue to operate as before, returning resources that conform to their original schema.

Extending the previous example, if the address field is restructured into subfields containing each constituent part of the address (such as streetAddress, city, state, and zipCode), this version of the resource could be exposed through a URI containing a version number, such as

{"id":3,"name":"Coderhop LLC","dateCreated":"2014-09-04T12:11:38.0376089Z","address":{"streetAddress":"109 TT street","city":"NY","state":"NY","zipCode":98053}}

This versioning mechanism is very simple but depends on the server routing the request to the appropriate endpoint. However, it can become unwieldy as the web API matures through several iterations and the server has to support a number of different versions. Also, from a purist's point of view, in all cases the client applications are fetching the same data (customer 3), so the URI should not really be different depending on the version. This scheme also complicates implementation of HATEOAS as all links will need to include the version number in their URIs.

Query string versioning

Rather than providing multiple URIs, you can specify the version of the resource by using a parameter within the query string appended to the HTTP request, such as The version parameter should default to a meaningful value such as 1 if it is omitted by older client applications.

This approach has the semantic advantage that the same resource is always retrieved from the same URI, but it depends on the code that handles the request to parse the query string and send back the appropriate HTTP response. This approach also suffers from the same complications for implementing HATEOAS as the URI versioning mechanism.

Note Some older web browsers and web proxies will not cache responses for requests that include a query string in the URI. This can degrade performance for web applications that use a web API and that run from within such a web browser.

Header versioning

Rather than appending the version number as a query string parameter, you could implement a custom header that indicates the version of the resource. This approach requires that the client application adds the appropriate header to any requests, although the code handling the client request could use a default value (version 1) if the version header is omitted. The following examples use a custom header named Custom-Header. The value of this header indicates the version of web API.

Version 1:

Custom-Header: api-version=1
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"id":3,"name":"Coderhop LLC","address":"109 TT street 98053,NYC"}

Version 2:

Custom-Header: api-version=2
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"id":3,"name":"Coderhop LLC","dateCreated":"2014-09-04T12:11:38.0376089Z","address":{"streetAddress":"109 TT street","city":"NY","state":"NY","zipCode":98053}}

As with the previous two approaches, implementing HATEOAS requires including the appropriate custom header in any links.

Media type versioning When a client application sends an HTTP GET request to a web server it should stipulate the format of the content that it can handle by using an Accept header, as described earlier in this guidance. Frequently the purpose of the Accept header is to allow the client application to specify whether the body of the response should be XML, JSON, or some other common format that the client can parse. However, it is possible to define custom media types that include information enabling the client application to indicate which version of a resource it is expecting.

The following example shows a request that specifies an Accept header with the value application/vnd.coderhop.v1+json. The vnd.adventure-works.v1 element indicates to the web server that it should return version 1 of the resource, while the json element specifies that the format of the response body should be JSON:

GET {"id":3,"name":"Coderhop LLC","dateCreated":"2014-09-04T12:11:38.0376089Z","address":{"streetAddress":"109 TT street","city":"NY","state":"NY","zipCode":98053}}
Accept: application/vnd.coderhop.v1+json

The code handling the request is responsible for processing the Accept header and honoring it as far as possible (the client application may specify multiple formats in the Accept header, in which case the web server can choose the most appropriate format for the response body). The web server confirms the format of the data in the response body by using the Content-Type header:

HTTP/1.1 200 OK
Content-Type: application/vnd.coderhop.v1+json; charset=utf-8

{"id":3,"name":"Coderhop LLC","address":"109 TT street 98053,NYC"}

If the Accept header does not specify any known media types, the web server could generate an HTTP 406 (Not Acceptable) response message or return a message with a default media type.

This approach is arguably the purest of the versioning mechanisms and lends itself naturally to HATEOAS, which can include the MIME type of related data in resource links.

Use API versioning as per your business need and how your APIs are consumed . In most of the cases it make sense to have some sort of versioning but make that call based on your use case understanding.