How to version REST URIs

RestVersioningClean Urls

Rest Problem Overview


What is the best way to version REST URIs? Currently we have a version # in the URI itself, ie.

http://example.com/users/v4/1234/

for version 4 of this representation.

Does the version belong in the queryString? ie.

http://example.com/users/1234?version=4

Or is versioning best accomplished another way?

Rest Solutions


Solution 1 - Rest

Do not version URLs, because ...

  • you break permalinks
  • The url changes will spread like a disease through your interface. What do you do with representations that have not changed but point to the representation that has? If you change the url, you break old clients. If you leave the url, your new clients may not work.
  • Versioning media types is a much more flexible solution.

Assuming that your resource is returning some variant of application/vnd.yourcompany.user+xml all you need to do is create support for a new application/vnd.yourcompany.userV2+xml media type and through the magic of content negotiation your v1 and v2 clients can co-exist peacefully.

In a RESTful interface, the closest thing you have to a contract is the definition of the media-types that are exchanged between the client and the server.

The URLs that the client uses to interact with the server should be provided by the server embedded in previously retrieved representations. The only URL that needs to be known by the client is the root URL of the interface. Adding version numbers to urls only has value if you construct urls on the client, which you are not suppose to do with a RESTful interface.

If you need to make a change to your media-types that will break your existing clients then create a new one and leave your urls alone!

And for those readers currently saying that this makes no sense if I am using application/xml and application/json as media-types. How are we supposed to version those? You're not. Those media-types are pretty much useless to a RESTful interface unless you parse them using code-download, at which point versioning is a moot point.

Solution 2 - Rest

I would say making it part of the URI itself (option 1) is best because v4 identifies a different resource than v3. Query parameters like in your second option can be best used to pass-in additional (query) info related to the request, rather than the resource.

Solution 3 - Rest

Ah, I'm putting my old grumpy hat on again.

From a ReST perspective, it doesn't matter at all. Not a sausage.

The client receives a URI it wants to follow, and treats it as an opaque string. Put whatever you want in it, the client has no knowledge of such a thing as a version identifier on it.

What the client knows is that it can process the media type, and I'll advise to follow Darrel's advice. Also I personally feel that needing to change the format used in a restful architecture 4 times should bring huge massive warning signs that you're doing something seriously wrong, and completely bypassing the need to design your media type for change resiliance.

But either way, the client can only process a document with a format it can understand, and follow links in it. It should know about the link relationships (the transitions). So what's in the URI is completely irrelevant.

I personally would vote for http://localhost/3f3405d5-5984-4683-bf26-aca186d21c04

A perfectly valid identifier that will prevent any further client developer or person touching the system to question if one should put v4 at the beginning or at the end of a URI (and I suggest that, from the server perspective, you shouldn't have 4 versions, but 4 media types).

Solution 4 - Rest

You should NOT put the version in the URL, you should put the version in the Accept Header of the request - see my post on this thread:

https://stackoverflow.com/questions/389169/best-practices-for-api-versioning/6750376#6750376

If you start sticking versions in the URL you end up with silly URLs like this: http://company.com/api/v3.0/customer/123/v2.0/orders/4321/

And there are a bunch of other problems that creep in as well - see my blog: http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html

Solution 5 - Rest

These (less-specific) SO questions about REST API versioning may be helpful:

Solution 6 - Rest

There are 4 different approaches to versioning the API:

  • Adding version to the URI path:

     http://example.com/api/v1/foo
    
     http://example.com/api/v2/foo
    

> When you have breaking change, you must increment the version like: v1, v2, v3...

You can implement a controller in you code like this:

    @RestController
    public class FooVersioningController {

    @GetMapping("v1/foo")
    public FooV1 fooV1() {
        return new FooV1("firstname lastname");
    }

    @GetMapping("v2/foo")
    public FooV2 fooV2() {
        return new FooV2(new Name("firstname", "lastname"));
    }
  • Request parameter versioning:

     http://example.com/api/v2/foo/param?version=1
     http://example.com/api/v2/foo/param?version=2
    

>The version parameter can be optional or required depending on how you want the API to be used.

The implementation can be similar to this:

    @GetMapping(value = "/foo/param", params = "version=1")
    public FooV1 paramV1() {
        return new FooV1("firstname lastname");
    }

    @GetMapping(value = "/foo/param", params = "version=2")
    public FooV2 paramV2() {
        return new FooV2(new Name("firstname", "lastname"));
    }
  • Passing a custom header:

     http://localhost:8080/foo/produces
    

    With header:

     headers[Accept=application/vnd.company.app-v1+json]
    

    or:

     headers[Accept=application/vnd.company.app-v2+json]
     
    

    >Largest advantage of this scheme is mostly semantics: You aren’t cluttering the URI with anything to do with the versioning.

    Possible implementation:

     @GetMapping(value = "/foo/produces", produces = "application/vnd.company.app-v1+json")
     public FooV1 producesV1() {
         return new FooV1("firstname lastname");
     }
    
     @GetMapping(value = "/foo/produces", produces = "application/vnd.company.app-v2+json")
     public FooV2 producesV2() {
         return new FooV2(new Name("firstname", "lastname"));
     }
    
  • Changing Hostnames or using API Gateways:

    >Essentially, you’re moving the API from one hostname to another. You might even just call this building a new API to the same resources.

    >Also,you can do this using API Gateways.

Solution 7 - Rest

I wanted to create versioned APIs and I found this article very useful:

http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http

There is a small section on "I want my API to be versioned". I found it simple and easy to understand. The crux is to use Accept field in the header to pass version information.

Solution 8 - Rest

If the REST services require authentication before use, you could easily associate the API key/token with an API version and do the routing internally. To use a new version of the API, a new API key could be required, linked to that version.

Unfortunately, this solution only works for auth-based APIs. However, it does keep versions out of the URIs.

Solution 9 - Rest

If you use URIs for versioning, then the version number should be in the URI of the API root, so every resource identifier can include it.

Technically a REST API does not break by URL changes (the result of the uniform interface constraint). It breaks only when the related semantics (for example an API specific RDF vocab) changes in a non backward compatible way (rare). Currently a lot of ppl do not use links for navigation (HATEOAS constraint) and vocabs to annotate their REST responses (self-descriptive message constraint) that's why their clients break.

Custom MIME types and MIME type versioning does not help, because putting the related metadata and the structure of the representation into a short string does not work. Ofc. the metadata and the structure will frequently change, and so the version number too...

So to answer your question the best way to annotate your requests and responses with vocabs (Hydra, linked data) and forget versioning or use it only by non backward compatible vocab changes (for example if you want to replace a vocab with another one).

Solution 10 - Rest

I'd include the version as an optional value at the end of the URI. This could be a suffix like /V4 or a query parameter like you've described. You might even redirect the /V4 to the query parameter so you support both variations.

Solution 11 - Rest

I vote up for doing this in mime type but not in URL. But the reason is not the same as other guys.

I think the URL should be unique (excepting those redirects) for locating the unique resource. So, if you accept /v2.0 in URLs, why it is not /ver2.0 or /v2/ or /v2.0.0? Or even -alpha and -beta? (then it totally becomes the concept of semver)

So, the version in mime type is more acceptable than the URL.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMike PoneView Question on Stackoverflow
Solution 1 - RestDarrel MillerView Answer on Stackoverflow
Solution 2 - RestZef HemelView Answer on Stackoverflow
Solution 3 - RestSerialSebView Answer on Stackoverflow
Solution 4 - RestjeremyhView Answer on Stackoverflow
Solution 5 - RestPete TerMaatView Answer on Stackoverflow
Solution 6 - RestJavier C.View Answer on Stackoverflow
Solution 7 - RestAsma ZubairView Answer on Stackoverflow
Solution 8 - RestUberSteveView Answer on Stackoverflow
Solution 9 - Restinf3rnoView Answer on Stackoverflow
Solution 10 - RestPaul MorganView Answer on Stackoverflow
Solution 11 - RestYarcoView Answer on Stackoverflow