
Best practices for API versioning? - melvinmt
http://stackoverflow.com/questions/389169/best-practices-for-api-versioning/
======
waterside81
As others have alluded to, it's all fine & dandy to try to adhere to the
guidelines of "pure REST" but in reality, you have customers/users who know
enough to construct a web request, but don't _really_ understand what HTTP
verbs are, what HTTP headers are etc. In my experience, your average developer
(of course, not anyone who'd frequent HN!) really doesn't have a good grasp of
how HTTP works. So the way you combat this problem is either

1) You provide client libraries in the popular languages so your users can
download those and not have to make requests directly. This way you can put
versioning and accepted response types in the headers instead of the URL

OR

2) You put everything in the URL and you're done with.

In my company, we initially went with 1) but then realized that just putting a
version & format (.json, .xml etc.) in the URL lead to much fewer "Your API
isn't working" emails.

~~~
MichaelGG
Sometimes I feel like I'm missing something, but then I read specs and I read
REST manifestos and I just don't see the value over RPC style. When coding
against an API, clients are pretty much always want to make "function calls"
and get values back. So even if the URL is just
"api.localhost.com/apiv1.handler" and everything goes into a XML or JSON body,
what's the drawback?

REST advocates insist that URLs shouldn't be constructed either. So every site
that boasts "REST" but then goes on to say accounts are at "/account/{id}"
aren't really RESTful. (You're supposed to find the account URI via a search
or save it from creation.)

Spreading the values of the "function call" all over the place just makes your
plumbing code more complicated, but the end result to the user will still be
"GetAccount(id) -> Account".

Plus, the concept of making the URIs all be nouns then cramming your logic
into the few HTTP verbs is just odd. OK, so HTTP has a DELETE method. Why is
that somehow intrinsically better than <action name="DELETE" id="123" />?

So far I've yet to see a _real_ REST API where I say "oh wow, that's a lot
easier to handle". Maybe I'm looking at it wrong, and ease-of-use for
programmers isn't a goal.

~~~
icebraining
I agree with you. For most people, switching to REST is useless, because
they're still attached to the conceptual framework of RPC. We're still in the
dark ages, re-writing the wheel again and again and again, coding clients for
each single service out there. It's not wonder that REST seems useless.

But there's a vast network of services, far bigger than all the RPC APIs out
there, that isn't like that. Where clients can connect to different services -
even services made years after them, with functionality they couldn't have
anticipated - without having to be tailored to them. Where the user can switch
the provider of a specific service without having to switch clients, because
the protocols are standard and compatible.

I'm talking, of course, about the HTML Web. Where people implement RESTful
services without even knowing what they are, just because following a standard
is just painfully obvious.

REST is the way we can implement something better; instead of dumb clients, we
can have smart agents that interact with the rest of the web as browsers now
do, but without the user hand-holding it. And gradually switching RPC to REST
is the only way to accomplish that.

~~~
mattmanser
REST is one of the stupidest ideas to have ever come out of HTML.

When you write a class do you only have 4 methods on it? Create, Read, Update,
Delete?

Case shut & closed.

But, but, but, I hear you say? It's not about the verbs, it's about the
intention behind the verb?

Any GET you do to the system inherently changes it. I log you accessed the
system, it often changes the way the object behaves (for example, you viewed
it, it is now more popular, it now appears higher in results).

I could go on for hours about how virtually every concept in REST is
_obviously_ flawed if you are an experienced programmer and simply _sit down
and think about it_.

It doesn't work!

So the concept was flawed from the beginning.

RESTful APIs died a long time ago, but somehow some people are hanging on to
the archaic meaning of REST without really realizing that 'REST' now simply
means 'API over HTTP'. The best APIs simply dropped supporting RESTful
interfaces a long time ago and those crazy people who stick to it, like
Google, have to contort their APIs into utter messes just to facilitate it.

Worse, people are still building entire systems based off its flawed nature.
Microsoft just released WebAPI which tries to force you into a RESTful model.
But then again, they never really have understood the web.

~~~
icebraining
_When you write a class do you only have 4 methods on it? Create, Read,
Update, Delete?_

Just because you are unable to stop thinking in terms of classes, doesn't mean
REST is flawed. REST doesn't have classes, it has resources, and they work
differently.

 _Any GET you do to the system inherently changes it. I log you accessed the
system, it often changes the way the object behaves (for example, you viewed
it, it is now more popular, it now appears higher in results)._

GET is not part of REST, it's part of HTTP, which is a particular
implementation of a RESTful architecture. The flaws of HTTP are irrelevant to
whether REST makes sense or not.

 _It doesn 't work!_

Your line is self-disproving, since you used a RESTful service to send it. The
web has literally billions of services following REST. The proof that it works
is shown again every time you click a link.

 _RESTful APIs died a long time ago, but somehow some people are hanging on to
the archaic meaning of REST without really realizing that 'REST' now simply
means 'API over HTTP'. The best APIs simply dropped supporting RESTful
interfaces a long time ago and those crazy people who stick to it, like
Google, have to contort their APIs into utter messes just to facilitate it._

Again, you've used a RESTful API to post this very message. RESTful APIs work,
it's RPC with a RESTful facade which doesn't, and it can't die soon enough.

~~~
mercurial
There is however one use case for which I haven't found a good way to use
REST: have the client upload a document to the server and return the same
document in a single call, transformed (say, applying an XSL server-side).
You're not really creating a new resource here, or accessing an existing one.

But I agree that in most cases, REST is good enough, and certainly a hell of a
lot better than old-style RPC or "let's-put-an-action-verb-in-the-URL-and-
call-it-REST" HTTP APIs.

~~~
icebraining
What happens if the connection is lost during the conversion? Do you really
want to force the client to send it again and redo the conversion? Is the
document time sensitive enough that it's better to repeat the process?

If not, then I'd say that it does make sense to create a new resource: the
document. You create it by POSTing the original, and the server returns a 201
Created, with a Location header pointing to its new URL. The client can then
GET it to download the converted version. The document resource should have a
TTL so that it can be pruned from cache.

I don't think REST fits all use cases, and RPC does make sense when your needs
don't fit the advantages of following REST, but I don't think that's the case
here.

~~~
mercurial
> What happens if the connection is lost during the conversion? Do you really
> want to force the client to send it again and redo the conversion? Is the
> document time sensitive enough that it's better to repeat the process?

No, I don't think it would be an issue to repeat the process in this case.

> f not, then I'd say that it does make sense to create a new resource: the
> document. You create it by POSTing the original, and the server returns a
> 201 Created, with a Location header pointing to its new URL. The client can
> then GET it to download the converted version. The document resource should
> have a TTL so that it can be pruned from cache.

I guess, but it forces the server to store the document somewhere (presumably
in RAM). It's much easier and cheaper in RAM to answer the POST with the
formatted document, and you also spare complexity client-side (only a single
HTTP call and only a single location for error handling). But yes, it would be
a possibility.

------
LukeB_UK
The top answer seems to have the mentality of "screw the consumer" when it
comes to versioning. If you have someone using version 1 of an api, when you
decide to make it version 2, you're essentially breaking their app by having
the reference change to the new one.

The answer even touches on the subject that it should be a permalink, yet they
then say that a new version should be the same url as the old one, which means
it's not a permalink! In my view, this is madness and potentially breaking for
people using your api.

In my personal opinion, you should set out with versioning in mind from the
start, otherwise by making even a slight change to your api, you change what
the consumer receives, potentially breaking stuff.

~~~
icebraining
It _should_ be the same URL as the old one. Just not the same content type.

The user /u/john of version 1 is the same user /u/john of version 2. You don't
want to break all links just because the client upgraded. Just reply with the
appropriate format for the version the client is asking for.

------
kevinpet
I'd like to see the subset of the answers from people who have actually
maintained a successful and widely used API. I'm skeptical that most clients
are sophisticated enough to deal with the pure REST dream.

Specifically, changing the JSON representation of, say, a list of account
activity, is perfectly compatible with REST. "Oh, you want /account-activity,
here it is, why yes, it does happen to be a list of links to /account-
activity/messages and /account-activity/transactions instead of the flat list
of things with a 'type' field like it was last week, but I'm directing you to
the resource, so it's all good"

~~~
pbreit
I worked on and supported a pseudo-API at PayPal for 7 or 8 years..."Web
Accept" and "IPN". 10s or 100s of thousands of integrations. 10s or 100s of
millions of payments.

No versioning.

It works really well. Once you add versioning, it's too tempting to add
breaking changes and just keep versioning. It becomes a total mess for
everyone.

~~~
almost
PayPals API certainly isn't the worst but it's pretty awful. So much pain
doing PayPal integrations. I assumed it just kind of happened but I'm shocked
if you guys thought it was good... See Stripe for an example of not to abuse
your API users.

~~~
pbreit
It's not perfect but I'd like to point out that it was born in 2000 and still
works fine today 13 years later. I think all the sample code I wrote is still
in the PayPal docs somewhere.

The most painful PayPal integrations for me were the SOAP ones.

------
leepowers
I always thought API versions in URLs had more to do with efficient URL
routing than RESTful semantics.

If you're Twitter or AWS and handling tens of millions of requests a day it
would (seem) far less resource intensive to determine routing based on a pre-
defined URL structure than to inspect the headers of each incoming API
request. It might also save development time. So you have your block of v1 API
servers and your block of v2 servers, without having to re-code the v1 stack
to also parse v2 requests.

~~~
schrodinger
Is it really any more resource intensive to inspect a header vs a url? Why?

~~~
leepowers
You can scan a URL very quickly:

    
    
        http://myapi.mysite/v1/user/new
        http://myapi.mysite/v2/tweets/fetch
    

The version identifier is always in the same place.

HTTP headers come in an _unordered_ list. And a client can send any number of
headers to the API. And the version identifier may be at the beginning of the
list, in the middle, the end, any position really.

Even so, I doubt the resource usage is very different per-request. But writ
large it may make a difference.

~~~
icebraining
GNU Grep can search for a string in 41000 files in 1.2s (that's with open(),
mmap(), close(), etc). I _really_ doubt that web frameworks are so optimized
that matching a particular header would take any perceivable time.

------
pbreit
I've never really cared for API versioning, especially the "/v1/" or whatever
in the URL.

Come up with a decent API design from the beginning; commit to backwards
compatibility, non-breaking changes, thorough testing and fast fixes; and
stick with it for a decade or so.

~~~
joncrocks
Which is fine as long as you aren't planning to change your product at all.

Yes, you can try and put it off for as long as possible, only making backwards
compatible changes. But it's likely at some point you'll need to change
something in your API, that simply won't work with existing clients.

~~~
pbreit
It's almost always possible to update APIs without breaking backwards-
compatibility.

------
pan69
The version thing is interesting. How do you maintain various current versions
of an API? If a URI cannot contain a version number (as the purists would
claim) then versioning happens in the underlying code base? If so, a client
still would have to specify a version, either in a query parameters, request
header or somewhere else.

In reality, if an API doesn't contain a version number in it's URI will almost
be impossible to maintain. To give a simple example, what if you decide to
switch technologies between API v1 and v2? How would you deal with that? Some
sort of abstraction layer I'd guess...

As far as I'm concerned, a version number in the URI makes the most sense.
They way I look at is is that /v1/resources/123 is a different resource than
/v2/resources/123.

So far, using a version number in the URI has worked out quite well for me
over time since I can isolate various code bases containing different
versions. Something that would not have been possible otherwise.

~~~
dllthomas
My understanding is that request header is the most standards compliant way.
In principle, you could certainly determine how you interpret the URL based on
that.

In practice, both clients and servers aren't really designed for that, though.
Particularly browsers, if you expect people to want to access/explore your API
that way.

------
begriffs
How is this even a debate? Versioning is a form of content negotiation just
like encoding, language, mimetype, and charset. Why treat this one extra
property any differently?

[http://blog.begriffs.com/2014/02/api-versioning-best-
practic...](http://blog.begriffs.com/2014/02/api-versioning-best-practices-no-
really.html)

------
keypusher
Why put the version in the URI at all? Can you not just use headers to request
and return particular version? Is there a downside to this approach?

~~~
simlevesque
As others have pointed, if you try to POST a HTML5 form to any API, you can't
specify the header, it will always be x-www-formurlencoded.

~~~
wprl
The thing is, this isn't all that important...

~~~
wprl
A down vote isn't a substitute for a valid reason why supporting vanilla forms
is an important point in the API versioning discussion ;)

------
yawz
I thought we'd already cracked this nut thanks to content negotiation.
Obviously not.

------
cullenking
We run an API with probably 20 registered consumers, supporting apps and
websites with different versions. This is not by any means an example of "the
one true way", but it seems to be working well for us.

Basically, we put together a simple wrapper that lets us automatically pick
which API version to use based on a users apikey, registered version (I set
them up with v1 or v2), and what they pass in. A before_filter automatically
pulls the apikey and version from params/headers, and it's consumed like this:

[https://gist.github.com/kingcu/1e5e6982ad3e05707303](https://gist.github.com/kingcu/1e5e6982ad3e05707303)

Essentially this lets us be strict about what key gets what result, and, lets
us do prioritized fallback logic by using the any() function shown.

------
_nato_
I think there is a lot of whimsy in what Don Knuth chose to do to version TeX
-- using pi (3.14) and moving the precision to the right upon every (though,
not often) version bump. Probably a little impractical for the rest of us, but
it's my favorite! `So creative!

------
euphemize
Agreed with kevinpet, I'd like to hear from people who built large, public
APIs. In my experience of doing this in the wild, it usually goes like so: you
develop a set of API calls, a client that talks to that API and release the
client. Then your director of product demands a change which requires a
modification in the data model. You need api versions to avoid your old
clients crashing if they use the new data model. Eventually your data model
stabilizes and you don't need versions so much, but in my experience, it can
take years.

~~~
danellis
Ideally your data model is identified by the media type, which would look
something like 'application/vnd.yourco.foo.v2+json', but in reality that will
get you a lot of blank stares.

------
joaomsa
I don't agree with the top response's recomendation of using redirects to
represent sunsetting of versions. That behaviour breaks POSTing. [1]

> Note: When automatically redirecting a POST request after receiving a 301
> status code, some existing HTTP/1.0 user agents will erroneously change it
> into a GET request.

[1]
[https://www.ietf.org/rfc/rfc2616.txt](https://www.ietf.org/rfc/rfc2616.txt)

~~~
dragonwriter
It breaks behavior in some misbehaving HTTP/1.0 clients at the time the
HTTP/1.1 RFC was written.

I'm not sure that that's a signficiant concern _now_.

Still, if the behavior has changed, 301 isn't appropriate for other reasons,
and if it hasn't changed, you shouldn't need a redirect at all, just handle
requests to the old URL.

------
Sarkie
This might be useful to look at from a real world point of view:
[http://davidwhitney.co.uk/Blog/2013/10/27/lessons-learnt-
sca...](http://davidwhitney.co.uk/Blog/2013/10/27/lessons-learnt-scaling-a-
big-mainstream-restful-api/)

------
brianbarker
This is the exact problem Hypermedia APIs set to solve. The second answer even
chimes in with that.

------
rjzzleep
you guys might be interested in the apigee api-craft google group, which
discusses a lot of these topics

[https://groups.google.com/forum/#!forum/api-
craft](https://groups.google.com/forum/#!forum/api-craft)

~~~
royjacobs
I have to second this. It's an excellent resource filled with sane people.

------
userbinator
The only thing I'd consider to be close to a "best" practice is to maintain
backwards compatibility. This means a little more effort initially put into
the design, but it pays off if it's to stay around for a long time.

~~~
yaur
and what if the guy before you didn't do that?

------
bpedro
You might also be interested in this article:
[http://apiux.com/2013/05/14/api-versioning/](http://apiux.com/2013/05/14/api-
versioning/)

