REST API versioning

In any client/server system, managing changes in the server can be challenging. RESTful web services are certainly no exception – especially publically available APIs. The consumers of a RESTful web service (the clients) rely on the web service to not break the contract.

Normally, the main concern will be to maintain backward compatibility. This means that if you update the server you must ensure that existing consumers will still work flawlessly.

There are several techniques to avoid disruptive changes and thus maintain compatibility – for example continuing to support existing query parameter formats, even if new ones are introduced, treating new query parameters as optional, not removing or renaming fields from resource representation bodies etc.

You should always do everything possible to avoid versioning of your web service (Cool URIs don’t change). However, even when doing your utmost, you might eventually find yourself in a situation where maintaining compatibility is impossible and some kind of versioning of your web service is inevitable.

Once you reach this point, there are two principal techniques to choose from:

  • URI versioning
  • Media type versioning

URI versioning involves including a version number in the URI. You do not necessarily have to version every resource of your service. Here is an example:

URI versioning is definitely regarded as good practice, and many well-known RESTful APIs uses URI versioning – for example LinkedIn and Groupon. However, the solution I will describe in more details is the other one: media type versioning.

Media type versioning is based on content negotiation using the HTTP headers Accept and Content-Type. The idea is that the web service, for each incoming request, has defined what version of a resource representation (aka. the media type) that it can consume and/or produce.

Likewise, when the consumer makes a request, it must include headers defining the version of the resource representation that it provides (if any) and the version of the resource representation that it expects to receive back (if any). Then the web service can easily detect whether it supports the provided/requested version of a representation. If not, it can respond with a well-defined error code.

The media types must be defined as so called vendor-specific media types. Vendor-specific media types are specialized alternatives to the standard media types such as application/xml, application/json etc. The vendor-specific media types can comprise information about the resource type (e.g. user), the version (e.g. v2) and the format (e.g. JSON):

Each GET request must comprise an Accept header defining the resource representation that the consumer expects to get back. In the below example, a request to get a representation of the user called john_doe is shown:

If the web service cannot provide the resource representation as stated in the Accept header, according to RFC2616, a response with HTTP error code 406 (Not Acceptable) shall be returned.

Each POST and PUT request providing a request body with a resource representation must provide a Content-Type header defining the resource representation. In the below example, a request to update the profile of a user called john_doe is shown:

If the web service does not accept the resource representation as stated in the Content-Type header, according to RFC2616, a response with HTTP error code 415 (Unsupported Media Type) shall be returned.

Here is a recipe on how this versioning approach can be easily applied in a Jersey (Java) based solution:

For each resource representation class, include a static field defining the vendor-specific media type. For a User class it can look for example like this:

In the web service class, use this static field when setting the media type:

The cool thing is that Jersey automatically responds with the correct HTTP error codes (406 and 415) if the media types (the versions) don’t match.

It’s my personal experience that the majority of contract-breaking changes in RESTful web services come from breaking changes in the resource representations rather than in the resource model of the web service – i.e. the URI’s (the resource identifiers) of your service. This is why, in many cases, the media-type versioning solves most of your versioning challenges – while keeping the URI’s of your service intact.

8 thoughts on “REST API versioning

  1. Hi Michael. your article was good. I need a sample code implementation of how the url versioning is implemented. how the server side code gets know that the specfic method is to be hit for the specific version url .. whether the url contains v1 text or 1.0 ?

    1. As stated in the article, I prefer media type versioning rather than uri versioning. Personally, I never used uri versioning, so I do not have an example of this. But there should be plenty of examples out there 🙂

  2. Hi. Your article was awesome. It helps me to understand clearly about API versioning. Some doubts arised. Could you please help me to clear.
    1. How the MediaType versioning maps the attributes?
    2. How it respond with different return types in the resource representation class?

    1. I am not completely sure that I understand your questions correctly, but maybe I can answer both of them in one answer: There has to be an exact match between the version numbers in the client requests and in the REST API. This technique does not provide backward compatibility. A client cannot produce an earlier version than the current version of a resource. For example, if the current version of a user in the API is application/vnd.mycompany.user-v2+json the API cannot consume or produce a user of version application/vnd.mycompany.user-v1+json – in case this is requested from an incompatible (older) client. The described approach is merely a technique to keep the URL’s intact (no version number in the URL itself) and to provide well-defined error codes (406 and 415) in case of a mismatch in the resource version numbers. It should only be introduced in the unfortunate situation, and only for the involved resources, where you see no other way than to break the compatibility. Let me know if this answers your questions.

  3. As explained in a previous comment, the solution that I suggest does not support older versions of resources. If you want to obtain this kind of backward compatibility, maybe you can find some inspiration in this blog post.

    1. Michael nice blog. The blog url mentioned above does not open for me. I would really love to know how backward compatibility could be achieved using media type versioning.

      Thanks
      PRasad

      1. Hi Prasad, Thanks for your comment. I contacted the owner of the mentioned blog. He is changing hosting solution, and asks for a bit of patience. The blog should be up and running in a few days. By the way, Troy Hunts sums up most of what is worth knowing about REST API versioning in this blog post

Leave a Reply

Your email address will not be published. Required fields are marked *