How to version REST URIs

2019-01-03 00:42发布

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?

11条回答
爷、活的狠高调
2楼-- · 2019-01-03 01:10

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.

查看更多
在下西门庆
3楼-- · 2019-01-03 01:10

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).

查看更多
【Aperson】
4楼-- · 2019-01-03 01:10

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.

查看更多
劳资没心,怎么记你
5楼-- · 2019-01-03 01:14

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.

查看更多
唯我独甜
6楼-- · 2019-01-03 01:15

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.

查看更多
Juvenile、少年°
7楼-- · 2019-01-03 01:20

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:

Best practices for API versioning?

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

查看更多
登录 后发表回答