Versioning REST Web Services

Managing changes to APIs is hard. That is no surprise to anyone who has ever maintained an API of any sort. Web services, being a special case of API, are susceptible to many of the difficulties around versioning as other types of APIs. For HTTP based REST style web services the combination of resources and content negotiation can be used to mitigate most of the issues surrounding API versioning.

Let’s assume you have a REST/HTTP web service that has some account resources. Say you can make a request like this:

===>
GET /accounts/3 HTTP/1.1
Accept: application/vnd.mycompany.myapp+xml
<===
HTTP/1.1 200 OK
Content-Type: application/vnd.mycompany.myapp+xml

<account>
  <name>Inigo Montoya</name>
</account>

First, you probably noticed that my example uses a vendor MIME media type to describe the representation. Using a more generic MIME media type like application/xml is much more common, at least in my experience. Using generic media types is perfectly legal but a bit silly. You are not really asking for any old XML document, but rather an XML document that has a quite specific schema. Aside from my idealistic rantings, using a specific media type has some strong practical benefits which are at the core of this post.

Backwards compatible changes

Often changes will need to be made to expose new behavior of the system that do not negatively impact correctly implemented clients. Say, for example, you want to start tracking email address for accounts. If the application/vnd.mycompany.myapp+xml format documentation is clear that elements that are not recognized should be ignored you can simply add a email element to the account representation.

<account>
  <name>Inigo Montoya</name>
  <email-address>mailto:prepare-to-die@youkilledmyfather.example</email-address>
</account>

Any client that was created before the addition of the email element will simply ignore it’s presence. Problem solved.

Incompatible changes

Unfortunately, not all changes can be implemented in a way that is backwards compatible. For example, a couple of months after adding email to accounts the sales team sign a deal for 1 bazillion dollars. But the new customer demands that each account be allowed to have more than one email address. After thinking for a while, you decide that the best way to expose that is by changing the account representation as follows.

<account>
  <name>Inigo Montoya</name>
  <email-addresses>
    <email-address priority='1'>mailto:prepare-to-die@youkilledmyfather.example</email-address>
    <email-address priority='2'>mailto:vengeance@youkilledmyfather.example</email-address>
  <email-address>
</account>

That, of course, will break any clients that are expecting the old format — so pretty much all of them. This is a place where we can bring content negotiation to bare. You can simply define a new media type — say application/vnd.mycompany.myapp-v2+xml — and associate new multi-email format with it. Clients can then request whichever format they want. Older clients don’t know the new media type so they get served the older single email format.

===>
GET /accounts/3 HTTP/1.1
Accept: application/vnd.mycompany.myapp+xml
<===
HTTP/1.1 200 OK
Content-Type: application/vnd.mycompany.myapp+xml

<account>
  <name>Inigo Montoya</name>
  <email-address>mailto:prepare-to-die@youkilledmyfather.example</email-address>
</account>

Newer clients do know the new media type so they can have access to the new functionality.

===>
GET /accounts/3 HTTP/1.1
Accept: application/vnd.mycompany.myapp-v2+xml
<===
HTTP/1.1 200 OK
Content-Type: application/vnd.mycompany.myapp-v2+xml

<account>
  <name>Inigo Montoya</name>
  <email-addresses>
    <email-address priority='1'>mailto:prepare-to-die@youkilledmyfather.example</email-address>
    <email-address priority='2'>mailto:vengeance@youkilledmyfather.example</email-address>
  <email-address>
</account>

Everyone gets what they need. Easy as pie.

Alternate approaches

The most commonly proposed approach for versioning REST/HTTP web service interfaces today seems to be to mutilate the URIs by inserting a version. For example,

http://foo.example/api/v1/accounts/3

I really hate this approach as it implies that an account in one version of the API is really a different resource than the account in a different version of the API.

It also forces clients into a nasty choice, either support multiple versions of the API simultaneously or break one of the core constrains of REST. For example, say a client exists for the v1 API that saves references (URIs that include the version indicator) to accounts. Some time later the client is updated to support the new version of the API. In this situation the The client can support both versions of the API simultaneously because all the previously stored URIs point at the old version of the API or it has to mung all the URIs it has stored to the point at the new API. Munging all the URIS breaks the HATEOAS constraint of REST and supporting multiple versions of the API is a maintenance nightmare.

Conclusion

Changes to REST/HTTP web service interfaces come it three basic flavors, changes to the properties associated with a type of resource, additions of new types of resources and deprecation of obsolete types of resources. If you are following the HATEOAS constraint of REST the approach described here can be used to safely handle all three scenarios.

This approach does lead to media types being created, but media types are cheap so we can — and should — have as many as we need. Used properly, content negotiation can be used to solve the problems related to versioning a REST/HTTP web service interface.


Related Posts

If you’re interested in REST/HTTP service versioning be sure not to miss the rest of the series.

Comments 2

  1. Benjamin Carlyle wrote:

    You hit the nail on the head, Peter. This is the right way to do it(tm), and the right way to use content negotiation. An incompatible (must-understand) change produces a new document type. Old and new clients are supported simultaneously based on their different Accept headers.

    Just make sure that every client always supplies an accept header from the very beginning of your project, otherwise you are stuck when you do need to make that incompatible change.

    In the long term you should still be aiming to minimise backwards-incompatible document-type change, and build widely-understood document types. Whatever problem domain you are in, you are sure to go through more than a couple of legacy content types before you settle on something that will stand the test of time.

    Posted 23 May 2008 at 6:38 am
  2. Bas van Westing wrote:

    Hi Peter,

    I really like this your approach.
    I used another approach to the same problem in my current application, by adding an “X-Restful-Interface-Version” header to the HTTP headers.
    But your solution makes much more sense.

    Regards, Bas

    Posted 17 Jun 2008 at 8:24 am

Trackbacks & Pingbacks 6

  1. From Peter Williams - Versioning REST Web Services (Tricks and Tips) on 13 May 2008 at 2:49 pm

    […] my previous post on this subject I described an approach to versioning the API of a REST/HTTP web service. This approach has […]

  2. From links for 2008-05-17 « Object neo = neo Object on 17 May 2008 at 5:31 pm

    […] Peter Williams - Versioning REST Web Services (tags: restful versioning webservices architecture) […]

  3. From Versioning RESTful Web Services « Ka anyi kwuo okwu on 18 May 2008 at 4:58 pm

    […] RESTful Web Services 18 05 2008 Peter Lacey posts here and here on how to version RESTful Web Services using custom MIME media types and I find this very […]

  4. From Peter Williams - REST/HTTP Service Versioning (Reponse to Jean-Jacques Dubray) on 18 May 2008 at 11:54 pm

    […] Dubray takes issue with my approach of using content negotiation to manage service versioning in HTTP. I actually hesitate to respond to Mr. Dubray because the overall tone of his piece is […]

  5. From codeoncotton » Blog Archive » Versioning REST web services on 19 May 2008 at 12:24 pm

    […] poring over versioning issues on RESTful web services i stumbled upon Peter Williams post proposing the use of vendor MIME media types to get the versioning under control. I really like […]

  6. From subbu.org on 19 May 2008 at 10:35 pm

    Avoid Versioning - Please…

    Peter Williams made some good posts suggesting content-negotiation as a means to advertise and ask for version support. This is in contrast to using version identifiers in URIs as is commonly done. This is a neat idea. Peter’s post prompted some debat…

Post a Comment

Your email is never published nor shared. Required fields are marked *