Hacker News new | past | comments | ask | show | jobs | submit login
Ask HN: Version numbers in a REST API
50 points by qixxiq on July 17, 2010 | hide | past | favorite | 49 comments
I'm in the final stages of designing a REST based API for my SaaS billing site, but I'm stuck debating whether I should include a version number (/1/clients/list) or not (/clients/list).

Obviously the latter is far cleaner and simpler, but am I shooting myself in the foot by leaving out the version number?

Actually, I think best practice is to not put the version number in the URI at all. Instead versioning should be handled via content negotiation. That is to say, a client specifies the type of resource they want back via the Accepts: header, and that resource is versioned. So A request would look something like:

GET /client

Accepts: application/vnd.clientlist.v1+json

And they would get back the version 1 client list response. If they want v2, etc, they can specify a different content type (clientlist.v2+json, etc). Also note, that putting verbs in your URIs is counterintuitive. The verb for a REST operation is the HTTP method (GET, POST, PUT, DELETE). The URI should simply represent the resource being retrieved. An argument can be made that the client list is the resource, but in reality listing things from a REST API is a first class concept and shouldn't need separate URIs. It's simply a request for a specific resource type without qualifying it by asking for a single instance of that resource. So, GET /client would return all clients (can add query parameters for pagination, etc), GET /client/834 would return a single client resource.

See also: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hyperte...

Can I have a few more upvotes please? This is the only way to do it. There's currently two root posts above this one advocating the incorrect way, with versions in the URL.

By doing it this way, you don't break links when you want to bump versions. Or if you have a single resource with an incompatibility, you can just upgrade the version of it, and leave all the others the same, without having to change anything, or your clients having to change theirs, either.

I wrote a blog post about this awhile back, please see point #4: http://blog.theamazingrando.com/your-web-service-might-not-b... (apologies for the formatting, I just imported it to Posterous, and it seems their styles aren't quite right)

Also, a former coworker of mine wrote a series of posts about this topic as well: http://barelyenough.org/blog/2008/05/versioning-rest-web-ser... http://barelyenough.org/blog/2008/05/versioning-rest-web-ser... http://barelyenough.org/blog/2008/05/resthttp-service-versio...

Isn't the point of bumping version to signal incompatible API changes? In that case breaking links is probably a better solution.

Answer needs more love. The capabilities of the client are part of content negotiation. The version that the client supports is thus also part of content negotiation, just like content format, language, character set, compression method, etc. are

Please do not place the version number in the URL, it is a horrible practice

Unless I'm mistaken, this basically tells me that I should put the same code for v1+json and v2+json in the same controller method, rather than actually dispatching to separate controllers. I'm not sure how it's done in Rails, but /v1/ and /v2/ are dispatched separately since they are different namespaces.

Also, how do you separate users accessing your API if not with X-* HTTP headers with an API key? (I'm referencing that link you posted). Would you not consider Gowalla (and hundreds of others who use X-* API key headers) as being RESTful?

In rails3 we could use constraints to limit requests to header x to be routed to controller x and vice versa for controller y. I dont tested it yet to be sure but I think its totally possible.

Please namespace your URLs by a version, such as "v1" (not just "1", which looks like a resource ID). If anything, this will motivate you even more to maintain backwards compatibility when you update your API, since there is nothing more infuriating to a developer than waking up one day to find an API call has changed (I'm looking at you Facebook).

Namespacing by version also is pretty "clean." Imagine updating your API in the future without the namespace. You'd have to implement the version in some difficult way (for the end developer) such as during authentication or as a request param or cookie or something ridiculous. This all adds complexity to the developers using the API. Its _much_ easier for a developer to just say "The prefix for all RESTful API calls is http://foobar.com/v1. No developer will say thats not clean.

So please, put a version number in your API, put it at the beginning, and put it in the "vX" format.

No, this is incorrect. If you have versions in your url, then the same client (eg, with ID 1) has two resource identifiers, /v1/clients/1 and /v2/clients/1. In fact, you have the same resource, /clients/1, but multiple versions of the representation. There's links further down, the one by Peter Williams in particular, that describes a way to do this using content negotiation and the Accept header.

Updating is easy, just add the representations to the resources that need the newer version (eg, "views" in rails). Updating with a new v2 in your URI means updating ALL your resources, or writing lots of redundant code to route multiple incoming uris to the same resource. This gets unmanageable, fast.

Putting versions in the URI increases complexity, for you, and writers of clients.

> Putting versions in the URI increases complexity, for you, and writers of clients.

Perhaps, but it you have tests for your api you can tell if you break them. Also, there is no reason you need to duplicate code if a section of the api didn't change. You only need to duplicate code if something major changes. Everything else can just be silently routed to the previous version's interface.

Thanks, my main problem was that /1/ did look dirty.

The /v1/ is much better, and solves the problem.

No, please don't do this. Having a version string in the uri is bad. The version means nothing about the resource, and everything about the representation. Please see some of the links further down in the comments for a more detailed explanation.

I've read through all the links, and whichever way I go its a compromise.

I'm choosing the /v1/ route because its a neat solution to the problem, it will work without serious issues and developers understand it easily.

Yes its not 110% REST, but I believe its the best solution to my problem. The fact that other major API's are taking the same route (Amazon,Twitter) just enforces the idea.

> Namespacing by version also is pretty "clean." Imagine updating your API in the future without the namespace. You'd have to implement the version in some difficult way (for the end developer) such as during authentication or as a request param or cookie or something ridiculous.

Why? Assuming the author is actually using REST, worst case for updating is adding another resource somewhere. There should be no need to update client applications at all.

There are many ways to do it.

From an "academic" point of view, the versioning through http accept headers is considered the "best one".

I'm usually going with a path prefix as nearly everyone else does.

As you probably have a lot of API users that don't know and care about http accept headers (and their connection libraries usually don't either), it might be a lot of PITA to convince them doing it right.

So imho you can use the "academic" solution and hire some API Support stuff, teaching each customer the benefits and ways to access versioned resources — or just use the most obvious de-facto standard like /v1/posts/<id>.

That's why I use this compromise.

In Addition, the http accept header versioning allows you to version on each resource independently. This might be a good thing but usually the whole API changes and not only one resource (change as in incompatible change, not an addition of some attributes)

I can't recall a single API I've seen or used that took the academic approach of using HTTP Accept headers. All of the major REST APIs I've seen have used API key X-* headers and most of them use versioned URIs.

It seems there are two REST camps: academics and those who actually write real-world APIs.

http://api.tenderapp.com. Course, I didn't work on it long enough to need another version :) I think I messed up by using a single version for the whole API. I think it makes more sense to have a versioned mime type for each resource (if that's how you choose to roll).

I think it depends on the change. If it's a major change, I'd change the URL and/or host. If I'm removing/renaming a field or otherwise changing the structure dramatically, then I think a custom mime type is appropriate. If I'm just adding a field (in the case of a JSON/XML object), then I probably wouldn't bother doing anything.

We also just had to research this as well for our API. Our solution is based on this - http://stackoverflow.com/questions/389169/best-practices-for...

This would always point to the latest API version: api.example.com/clients/1/posts

If you want a specific version you do this: api.example.com/v1/clients/1/posts

Since we're using ASP.Net MVC we could register a 'route' which points api.example.com/ to the API v1 code. Then when /v2 comes out we just point it to that and v1 is still available.

I'm not sure how I feel about that. Then you're going to be ok with making backwards-incompatible changes, but a lot of people may change to them immediately because they're not using the versioned url.

If you were to go that way, I would recommend strongly encouraging developers to use the /v1/. "It's 3 extra characters to make sure that your app doesn't break one day because we upgrade the API." Obviously, you probably should make backwards-incompatible changes infrequently and only after communicating well with your developer community--otherwise developers will feel like they can't keep. But still, some people will miss the announcements or not have time to adapt in time.

You're right, but this is the side effect of 'releasing early' and responding to custom feedback. You're usually safe to make drastic changes when its just the web application but APIs are a different story. The world of APIs is about stability and backwards compatibility, but sometimes this just isn't possible. If you remove a feature or drastically change how something behaves then it isn't possible to make it backwards compatible. If it is a drastic enough change then even the version numbers won't save you. Perhaps you completely changed how some data is persisted or queried. Its really hard to justify keeping old/broken things around when you probably just wrote and released that a month ago and now you've taken a different approach.

In the end, it seems how APIs are versioned and supported completely depends on the maturity of your product. I imagine that eventually you want to get to the point where you're only adding to the API and not removing or reworking entire calls. And perhaps then you won't need the version numbers at all. But for now, they might be your only safety-net for your customers.

I would hope that if the maintainer of an api was planning on making a not-backwards-compatible version change they would put a hell of a lot of time informing people about it.

That way, people who need to stay on old can add in the string, and those who can adapt will.

The v1 just doesn't seem to belong in that part of the url to me. Maybe if you had v1.api.example.com/coolstuff/1 - that I'd be more comfortable with.

Wow, I guess I got to work on my research skills a bit more.

Spent the last two hours looking for suggestions but didn't find half of what you just posted (probably because I was missing the key word 'versioning')

What would be the problem of including a number? one more (static) segment in the url. Just do it, if it makes (or will make) your life easier.

However, I would name them "v1", "v2" etc. That makes the purpose of the number clear.

Hmm.. I don't really see the need for versioning in REST APIs. Webapps don't have versions, because it's smarter to just push small changes continuously. Your API maps functions in this changing application - keeping an old API around isn't like keeping an old version of Word around. If the app changes so a given API call won't work any more, it won't magically keep working because of versioning...

It doesn't add much value to give users a /v2/ to call, if it's not because that /v2/ will keep working independently of changes to the app. If it stops working some time because you're changing your app, you'll still have to inconvenience your users by pulling an old version out of production. On the other hand, there's no point in forcing users to upgrade to a "new" API, if the new API doesn't do anything the old one didn't.

No reason you couldn't just deprecate what will stop working on a method-by-method basis instead. If you pair it with application-keys, you'll know which users are using the methods you're about to deprecate and talk directly to them about transitioning away.

When something less radical changes, you can add new parameters and add new fields in the response just fine, without invalidating the old version - and if you can't, add a new method, e.g. /clients/list_with_invoices/ as the new version of list.

Yea having to version a "REST"ful api usually means its a was not very restful in the first place . Meaning the api is not hypertext driven and is probably a rpc style api with meaningful urls. If it was hypertext driven it would all be transparent to the consumers , it could be v2 or foobar , doesn't matter .

I like the approach that Peter Williams has suggested. That is to use a vendor MIME media type in the Accept header to specify a required API version. At least your URL stays the same. As it should be, because your resource is still the same.


How about putting the version number in the hostname?


I believe its a little neater than /v1/clients/list, albeit a little less standard.

You should incorporate the API version.

  - you're developing a service would typically be a core part of your client's businesses
  - the API will almost certainly need be revised after you release it
  - even if you choose not to support deprecated versions, you will need to give your clients enough time to switch
  - that means that there will be periods where at least two versions of the API will be live
  - and both versions will need to be live on their final endpoints

Definitely do it. Having the "/v1/" (I agree with the comments that the v is better.) is still plenty "clean". No one is going to say "well, I was going to write an awesome app with their API, but those 3 extra characters to make sure my app doesn't break made it too much of a pain."

Also, think about rolling-out backwards-incompatible changes otherwise. People want their apps to work immediately before you roll out the backwards-incompatible changes and immediately after. This means that for a period of time, you're going to have both up as they do the transition. (Your only other option is to say "at exactly 8:00 PST we're going to make the change. So deploy your changes that adapt to the change at exactly that time so you don't have downtime.) It's a lot cleaner to use versions and have them switch their urls from /v1/ to /v2/ whenever they feel like it. Otherwise, what are you going to do? You need api.yoursite.com to stay the old version so you don't break apps that haven't switched yet. So you'd have to do something ugly like have people switch to new.api.yoursite.com to get the newer version. Then, once you've disabled the old version and had api.yoursite.com, you have to get everyone to switch back to using api.yoursite.com because pretty soon, new.api.yoursite.com is going to be the following version. (Or you could make that version newer.api.yoursite.com, and then the next one newest.api.yoursite.com, and then you're really screwed when you need the next version.)

Basically, the cost of versioning your API is very low, and the potential headache of making backwards-incompatible changes without it is huge. Just do it.

If you're not sure how you want to do this, you could always wait until you need to implement version 2. You would then be forced to have omission of a version number indicate version 1, but waiting would allow you to make the decision when you're actually ready to begin implementation and might have a better idea or more information about how you want to approach it.

Use versions like /v1/ .

If there's no version... * If there request is plain html then deliver a human readable documentation page (that still has hyperlinks for discoverability. * If the request is asking for whatever your application type is, redirect to the current stable version.

If there's an older version requested: * If it's no big whup, keep the old version usable. Sometimes I do this by just keeping the old version of the resource code around, sometimes by updating it to translate between the old version and the latest stable version. * If you want to kill an old version, think about what appropriate in terms of 300 Multiple Choices, 301 Moved Permanently, or 410 Gone relative to your users.

Just put a version number in the API root -- it really doesn't matter where. http://api.mysite.com/1/ , http://api.mysite.com/?version=1 , etc, anything will work. In fact, you can support multiple styles easily.

Since it's REST, clients shouldn't be hardcoding any URLs aside from the API root. Therefore, if you think a version is ugly, you can make the sub-URLs unversioned for now and version them later if needed.

I had the same problem when designing a REST API a while ago. After reading lots of documents on REST philosophy I decided that no one really knows what REST is and there is no precise answer.

In our case, we decided to go with the version number in the API (I don't think it matters if you use "1" or "v1"), because we wanted to be able to easily route requests to various API versions in the future (using load balancers). But it's more a matter of taste than a hard technical decision.

Make sure you can easily route requests for a particular version to a different back-end server.

If you in the future decide to write the next version of your webservice using a different technology (e.g. going from python to node.js or whatever), you want your front-end server (e.g. nginx) to direct the traffic to the correct back-end without too much trouble.

How about /version that your client can GET and see which is expected/required/supported?

You can also negotiate the version number in the HTTP header:

  X-protocol-version: 3
That way you don't need to pollute the address space.

Don't do that. Companies routinely introduce routers to load-balance service hosts, and some of their bright ideas include using "Service Appliances"; crap that strips headers.

I had to take packet snippers to XML appliances :-/

API versioning is a good thing, and the best way to choose a version is via a parameter. Don't ever ever try to to encode the version into the security token you return to the clients; someone did that for succinctness, so that you could choose a version once upon connection establishment. It was a nightmare to debug looking at the logs.

With API design, your good design decisions will be taken for granted, and your bad ones will me immortalized in a mountain carving. Try to model it after some existing API that offers a similar functionality, or use an extensible design like the SugarCRM SOAP API, or Zuora's SQL-like one.

Are there any other disadvantages of this approach other than the problem with "Service Appliances"? Many REST APIs rely on HTTP headers for other things - do "Service Appliances" only remove non-standard headers?

If you can imagine a stupid, pointless, wrong way to deal with network traffic, there is an appliance somewhere doing it.

I once saw a significant uptick in users being unable to use an AJAX application because a developer "fixed" the RPC stuff to sent Content-Type: application/json headers instead of claiming to be text/html.

I think it is okay.

E.g. if you are programming GData client, it suggest you to add version info (i.e. GData-Version: X.0 ) in the request header.


Putting a version number in an arbitrary header or the URL requires a layer 7 load balancer whereas using a different hostname (v2.api.com) can be repointed with DNS.

Maybe, but what do I do if the header is missing? Use the latest version?

If I use the latest version it is likely developers will simple leave the header out since it "Just Works" without it.

Then when I make a breaking change to the latest API those applications will get screwed. Yes its mostly their fault -- but its my problem.

If the header is missing you could return a 4xx response. You could document that the header is required or return a message in the response body indicating the cause of the 4xx.

If client missed the version information in their request, you can send the request to the earliest supported version of the API by default.

This is how Google handle it and I think it make sense. http://code.google.com/intl/zh-TW/apis/gdata/docs/developers...

personally I would put the API version as an argument to the URL and I would make it a requirement. Most developers likes strict requirements, no developer likes surprises either.


If the version isn't there just return a useful error.

The only downside to this is that it's slightly more difficult to do analytics on the URL requests coming in.

The #1 danger to your API's usability is the half-assed implementation a 3rd-party will release to the public without your prompting or involvement. Don't let that happen. Take initiative and release libraries for as many languages and frameworks as you can, or risk the danger of being sabotaged by someone's indifference, or most likely incompetence.

You can't believe how many time I have had problems with an API just to discover the 3 year old client library was using some "sensible defaults" for required arguments.

You can also embed the version number in the API call itself, using a default if not passed or auto detecting based on what is passed.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact