Best practices for API versioning?
stackoverflow.com
stackoverflow.com
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.
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.
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.
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.
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.
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.
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.
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.
And the HTML Web is NOT RESTful. Plenty of sites return different results for a URL, break links, have non-idempotent GET, don't return the created item's URL on POST, etc.
So when people talk like this about API-driven stuff, it sounds like UDDI or some magic dream. Can you draw a direct line to what kind of code is gonna be written? Or is this like a "well if we invent AI-like stuff then it'd be nice because AI won't be able to figure out RPC?" Maybe I'm being dumb and unimaginative.
>Maybe I'm looking at it wrong, and ease-of-use for programmers isn't a goal.
IMO, ease of use for the programmers using the API is not the goal. Ease of maintenance is the goal. Basically RPC is bad because it is an extreme tight coupling between client and server. Change one single parameter in one single SOAP method? Get ready for every single client to have to recompile. Even the ones that never used that particular method (there are techniques to minimize this, but with REST you don't have to think about this problem).
REST is about loose coupling. If you follow HATEOAS properly the clients won't even need to recompile if you do a massive refactoring of where your resources are. So long as you're not doing direct serialization of the XML resources, you also won't have to recompile for every tiny schema tweak. If a field you use changes, obviously you have to change the client. If a field you don't use changes you probably don't even need to restart your client.
This is what it buys you. If you don't get any benefit from the loose coupling then you don't need REST. But if that's the case then I wonder if you need a three tiered system at all.
If you use a single endpoint like "/service" and POST bodies, then there are no "resources" to locate in the first place, so no problem when changing your URI schema. "GET /service?type=account&id=123". Or even just "POST /service {body Action=GetAccount Id=123".
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.
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.
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"
For the versioning, we developed VersionCake. https://github.com/bwillis/versioncake/
For each jbuilder view, the version number is contained within the file name. E.g.
index.json.v1.jbuilder
index.json.v2.jbuilder
index.json.v4.jbuilder
The client passes in a version number and VersionCake intelligently renders the appropriate view version or degrades to a prior version when the specified versioned view doesn't exist.Works like a dream.
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.
Yes, I agree with the idea of enforcing backward compatibility as much as possible and, when that fails, make it a social problem (documentation, email, advance notice...).
But being in the midst of one of those PayPal integration... oh my, what a mess!
* The sea of DEPRECATED in the documentation (hide it away?)
* The pervasive inconsistency in everything
* The choice of x-www-form-urlencoded for IPN data... (I'm trying to figure out some charset bug at the moment)
Anyway... :) No hard feelings!
The most painful PayPal integrations for me were the SOAP ones.
There's nothing in REST that opposes versioning either. All it says is that you shouldn't use the URLs for it, since then if the client wants to upgrade, it'll break all his stored links.
Versioning can be handled just fine by having the client request the media type with the version he needs, e.g.:
Accept: application/users-list+v1
And if it asks for that, you should definitively give it the v1 format, not throw the v2 and let it deal with that.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.
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.
A request has a much better chance of getting cached reliably if all the important semantics are in the path than if they're in arbitrarily-ordered querystring args or headers. Squid's default config didn't cache anything with a querystring up through v3. OldIE wouldn't cache an uncompressed response with any Vary headers. I suspect there are landmines like this buried all over the place.
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.
No function should be promoted to the core API without serious consideration. Instead use something like /alpha/function-v2.2/ for testing functions that may disappear or be updated, making it easy for clients to write workarounds for these non permanent functions.
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.
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.
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.
It happens in the underlying code base whether or not it is reflected in the URI; one "pure" REST would have it in the Content-Type, but that's problematic with pure-HTML forms.
http://blog.begriffs.com/2014/02/api-versioning-best-practic...
Edit: Looks like this may not be possible on a HTML 5 form.
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
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.
> 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.
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.