Best way to handle JAX-RS REST API URI versioning

Deepesh M picture Deepesh M · Feb 12, 2013 · Viewed 17.3k times · Source

I did my search first in stackoverflow & I was not able to find out any answers related to my question. All I can find was questions related to REST uri design.

My question in on the backend side. Suppose we have two different version of REST uri's

http://api.abc.com/rest/v1/products

http://api.abc.com/rest/v2/products

What is the best approach to follow on the backend side (server side code) for proper routing, manageability & reuse of the existing classes across these two set of api's based on version?

I have thought of approach to define resource classes with different @Path annotations for e.g. have a package for v1 & v2 separately & in ProductsResource class of that package, define

    package com.abc.api.rest.v1.products;
    @Path("/rest/v1/products")
    public class ProductsResource {...}

    package com.abc.api.rest.v2.products;
    @Path("/rest/v2/products")
    public class ProductsResource {...}

& then have the implementation logic based on the versions. The problems with this approach is when we are only changing one particular resource api from the set of api's, we have to copy other classes to the v2 package also. Can we avoid it?

How about to write a custom annotation say @Version & have values of the versions it supports? Now whether it is v1 or v2, both request will go to same resource class.

Say for e.g.

    package com.abc.api.rest.products;
    @Path("/rest/{version: [0-9]+}/products")
    @Version(1,2)
    public class ProductsResource {...}

UPDATE:

There was a API versioning suggestion by Jarrod to handle version in headers. That's also one way to do it however, I am looking forward for best practices to use when we are following URI based versioning

Answer

user177800 picture user177800 · Feb 14, 2013

The problem with putting it in the URL is that the URL is supposed to represent a resource by location. An API Version is not a location and it not part of the identifier of the resource.

Sticking /v2/ in the URL breaks all existing links that came before.

There is one correct way to specify API versioning:

Put it in the mime-type for the Accept: header that you want. Something like Accept: application/myapp.2.0.1+json

Chain of Responsiblity pattern goes well here especially if there will be significant number of API versions that are different enough to have to have their own handler, that way methods don't get out of hand.