Best way to handle JAX-RS REST API URI versioning

18,439

Solution 1

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.

Solution 2

This blog post has an example of what is considered the by some to be the correct approach, i.e. not having the version in the URI: http://codebias.blogspot.ca/2014/03/versioning-rest-apis-with-custom-accept.html

In short, it leverages JAX-RS @Consume annotation to associate the request for a particular version to a specific implementation, like:

@Consumes({"application/vnd.blog.v1+xml", "application/vnd.blog.v1+json"})

Solution 3

I was just wondering why not have a subclass of ProductService called

@Path(/v2/ProductService)
ProductServiceV2 extends ProductService {


}


@Path(/v1/ProductService)
 class ProductService{


}

and only override whatever is changed in v2. Everything unchanged will work the same as in v1/ProductService.

This defintely leads to more # of classes but is one easier way of coding for only whatever is changing in the new version of api and reverting to the old version without duplicating code.

Share:
18,439

Related videos on Youtube

Deepesh M
Author by

Deepesh M

Updated on June 05, 2022

Comments

  • Deepesh M
    Deepesh M almost 2 years

    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

    • Admin
      Admin about 11 years
      best practices is to not put api version information in the URL
    • arcseldon
      arcseldon about 10 years
      This was a great question, I am very surprised at the lack of responses. There are hundreds of people arguing for and against URI versioning but all the major sites do it because it is explicit and easy for clients to use. @Deepesh M - what solution did you use in the end?
    • Admin
      Admin almost 10 years
      just because lots of people do things incorrectly doesn't make it a good idea! it just means lots of people are doing it incorrectly.
    • Osama Khalifa
      Osama Khalifa over 7 years
      I think having the version at the URL is against the REST concepts, As from REST perspective "v1/users" means that you are trying to get "v1 users". A good solution may be having it at the request header.
    • Morten Nørgaard
      Morten Nørgaard almost 6 years
      This is a religious question, and 'best practice' in your case is likely 'what works best for you, in co-operation with the users of your API'. This question stackoverflow.com/questions/389169/… outlines some fine strategies.
  • cmonkey
    cmonkey about 11 years
    Tacking on to this - in a RESTful application, your URL should represent a resource. The resource probably isn't 'versioned'; it's the same regardless of access style. If the resource is versioned, it should be represented within the resource, not in its identifier.
  • Deepesh M
    Deepesh M about 11 years
    @cmonkey, can you give an example?
  • cmonkey
    cmonkey about 11 years
    Example: my user account is a resource on SO. The url is: stackoverflow.com/users/322722/cmonkey. When/If SO changes features, apis, or adds data to my user account, the account is still the same resource. It would not suddenly become http://.../cmonkey_v2. Otherwise, linked content (like this comment) will no longer work.
  • Deepesh M
    Deepesh M about 11 years
    Okay. I presume you are saying the resource stays the same but version should be there in header to have a differentiation between SO before & after changes.
  • Deepesh M
    Deepesh M about 11 years
    Okay, I am inclining towards having the version at the URI level. Reason being in URI is, it is noticeable & easy to handle by the api consumers. However, it was a good suggestion in case if anybody want to achieve the versioning using headers. I will edit my question to make it for uri specific versioning.
  • Admin
    Admin about 11 years
    @DeepeshM you are going to regret it I know from experience!
  • Alex
    Alex about 9 years
    If the structure of the URIs change, the URI needs to have the version. stackoverflow.com/v1/users/322722, stackoverflow.com/v1/users/322722/questions, stackoverflow.com/v1/users/322722/answers, stackoverflow.com/v2/accounts/322722, stackoverflow.com/v2/accounts/322722/gaps, stackoverflow.com/v2/accounts/322722/rants,
  • jFrenetic
    jFrenetic almost 9 years
    That was my initial thought also :) I recalled how EclipseLink implements support of JPA dialects in a similar way (Oracle11Platform extends Oracle10Platform, etc.). But then, I figured it's going to be very messy with REST. Just imagine having to extend all of your classes version after version. I like the approach with Header parameters.
  • Admin
    Admin over 8 years
    This is so short sighted it is not even funny. You are going to have to maintain 30 different methods or classes for every URL in your application when you get to v30? Does not scale.
  • Roman Vottner
    Roman Vottner over 7 years
    In a true RESTful environment it doesn't matter where the versioning construct is kept or how the URI is designed. A RESTful client has no information regarding the service except for its starting URI. Everything else is learned through request and responses. If a versioning update occurs the client is still requesting the same starting-URI as it may have used before. The server, however, is now returning something different. If the content-type remained the same and only the URI changed slightly, the client might not even notice a big difference.
  • Roman Vottner
    Roman Vottner over 7 years
    If the content-type changes though, the client might not be aware of what the response is all about and therefore might not be able to interpret the result and learn further actions (HATEOAS) unless it is able to find the content-type specification and is further able to interpret it.
  • Roman Vottner
    Roman Vottner over 7 years
    Who defined what is considered the correct path? REST is an architectural style and no protocol! Unless you violate HTTP or do not adhere to the architectural constraints there is no right or wrong, maybe some best practices though some self-claimed REST services aren't RESTful in any way therefore certain statements should be treated with special care.
  • David Dossot
    David Dossot over 7 years
    You're right, I've toned down and added "by some to be" to emphasizes that not everyone agrees.
  • Kwebble
    Kwebble over 7 years
    @RomanVottner this can be handled by letting the client specify the types it understands in a Accept header in the request.
  • gdbj
    gdbj about 5 years
    If the changes are minor, I'm not sure why you couldn't do this. You'd only override the methods that have changed. If you are adding new methods and deprecating old ones, then couldn't you can choose a different pattern at that point?
  • ShraddhaJ
    ShraddhaJ about 4 years
    We are also thinking about the same approach of extending class. We are using resteasy + swagger. What kind of other apporoches are available ?