Nobody Understands REST or HTTP
blog.steveklabnik.com
blog.steveklabnik.com
Very lengthy discussion at that time.
At worst, the page in question uses automatic translation (not so uncommon when it comes to large knowledge bases), so the translation might be odd.
Basically, according to the article, Wikipedia has it all wrong.
While putting the version into the header is clever, it reduces the usability of your api. When you are designing a RESTful api you typically want to design your api so that it is simple and easy to implement. Nothing is easier than being able to explore an api via a web browser. If you make the user specify versions in the header than they will have to install a browser plugin to explore your api.
You have to consider that you aren't always "selling" to other developers who understand http headers. You could be "selling" to non technical project managers and CEOs who simply don't understand http headers. They do understand URIs, though. So if you can provide these people with a URI that just works, and they can poke around and see data they have a greater chance of understanding and getting excited about your API.
Also, what about custom HTTP verbs? Many times I need something more than GET/PUT/POST/DELETE. What happens then? I haven't seen anyone talk about that.
Some of the points of contention:
(1) Should api version go in the URL or accept header?
(2) Should representation type go in the url or accept header?
(3) Are custom HTTP verbs okay?
(4) Should GET, POST, PUT and DELETE map one-to-one to CRUD? Most say no, but other seeming authorities say it's fine.
(5) Should you ever return a URL template, and a set of entity identifiers that can be plugged in, or should you only return the fully formed URLs?
(6) What is the difference between a URL and a URI? (And all you who say this one is dead simple and I'm an idiot for not knowing, see if your answers actually agree with each other)
(7) Are two different language translations of a document different resources, or are they different representations of the same resource?
(8) If two different language translations are just different representations of the same resource, how should the client indicate which version it wants?
And of course some people say that a few of these questions aren't even within the scope of REST anyway.
1. Possibly both (the one in the URL being the version of the URL-space and the one in the Header being the more fine grained Representation Version).
2. It depends. For simplicity it often makes sense to put it in the URL. For more generality headers can be better.
3. No
4. They don't have to. They usually do though and it makes most sense when they do.
5. Fully formed URLs are simpler, so go with those if you can. But sometimes you'll need more.
6. URLs are a subset of URIs. All URLs are URIs. URLs give the location of the resource whereas URIs just have to identify it (but could also give the location of course.
7. It depends. I lean towards different but I'm no authority.
8. Using the Accept-Language header. But I'm guessing this is not always the best way to do things.
But more important that is upgrading a version on an API may not be an all or nothing thing. You might want to start using the new features of the API on one resource type but you aren't ready to upgrade your usage on everything else. If the version is in the API you'll have to take apart and put back together urls to get the right ones, this is logic you don't want to have to encode into your client. If on the other hand you use Accept headers to do versioning you can have as fine grained control as you need.
Regarding the custom HTTP verbs it may seem like you need those at first but in practice you really don't and there is almost always a good clean way of doing things that doesn't break anything (or so I've found). I find that the solution is usually to introduce another resource or two, the transactions example from the article is a perfect example of this.
I know it sometimes seems like this is all abstract stuff that has no impact on the real world but it does make sense eventually! It's really lovely to use a properly RESTful API :)
Of course version numbers in URLs can have their place too. But I think they should only really be used in situations where you have upgraded so much that the original URL space just makes no sense. And if you can avoid huge breaking upgrades like that through good initial design then all the better :)
I think for a lot of people the reason they don't see the benefit of things from REST is they try to use them in isolation. You say "this is useless for my RPC style API!" and you are right.
FWIW, I've made an effort to follow the purity of it, but the APIs I see that try to do true ReST are insanely obtuse. If you know of any real world case studies where a provider went from "fake" ReST to true ReST, I'd love to read it. The contrived examples are not helping me out in the comprehension department.
Typically you don't release a new version until you need to do significant changes to the entire layout of your api. In which case the old version is not even relevant. With this in mind, you would not want to promote using a new version of the api for one resource with an old version of the api for another resource.
Just thinking about it sounds dirty. Your migration strategy should include sufficient time for you to assist your clients to move to your newer versions.
api.example.com/v2/account
or api.example.com/account Accept: application/vnd.steveklabnik-v2+json
And I'm not talking about how easy it is for Developers to understand. I'm talking about how easy it is for Everybody to understand.
if you do it "wrong" you probably store record ids in your local db and then access stuff from the API by constructing your own urls.
a more proper way of doing it is to store the compete resource urls and not just ids. but in this case you have a version update problem. When you release a new version of the app that supports new version of the API you will now need to go over all the stored resource urls and update the version, probably doing some regexing etc.
with version in the headers you can store full resource urls and not have to change them every time api version changes.
I think that not only is using accept headers worse, I think it is flat out wrong. That's not what the accept header is for. It's for client specific things only.
The version of the API you need is NOT client specific.
A situation that may arise is people not even aware they are using the wrong version of the api. And which one do you default to? Do you start with the version header always or do you add it into the system on version 2? Then do you require the version header? What happens if you didn't add that in version 1? Which one do you default to the new one? Is it really easier to change one line header than one line service prefix?
It is much much easier when maintaining a large service with more uri focused api routes/actions/verbs at times. It still is defined as rest but has some rpc elements to it. You don't even have to go down to the the model like /api/profile/[uuid]. You can do things like /api/signup /api/login and match those sensible abstractions into the rest api that lives above the model layer. This is always more flexible for minimizing versions and allowing core model changes without having to change much and provides a better consumer experience of the api. This is more of a REST and RPC mix that works well if you have to work with things beyond just backend services such as games, interactives, scripted experiences etc.
I make services fully RESTful when I can but I have to build services that run in scripted clients without easy access to headers, this is where header based versioning is more difficult for the consumer of the service. What I have been doing is looking first for a header, then for the url version, the routes are abstractions anyways so I route those accordingly.
I am liberal in what I accept, conservative in what I send like a good service should be.
You can use System.Net.* but if you want support across iOS, Android, Web, and Desktop you need to use WWW. Which does not allow you to read or set headers.
I have decent services working with it in JSON using LitJson but it is something they should work on and has prevented me from using headers much in Unity. Even the WWWForm class is weak but there are hidden methods to set and read headers, just they don't work on all platforms yet.
My biggest hiccup in making true REST has actually been in games where web standards and tools are still pretty fresh. So many C/C++/C#/Python/Lua etc proprietary web libs that to make things work you have to have some fallback to uri based states or resources. I typically implement that as a fallback i.e. the version 1 api with headers or url route to the same place.
Thanks for the info :)
If I'm viewing some resource in some client that supports version X and I send it to you and you view it in a client that supports version Y (maybe this happens automatically, maybe new versions are in the process of being rolled out, maybe your on the mobile client that hasn't been updated yet) isn't it better that my client gets a representation of it that it can understand?
(I don't think there's one answer for everything, I think both can make sense in different situations. But I think versioning via Headers can be very powerful and can interact well with of RESTful types of things you might want to do, it would certainly make no sense in an RPC style API)
If you need to perform some action that can be expected to take time, you can issue a POST request, which can give you a new resource that reports back on its current state. An example could be: POST /printer with the request body containing the document to print. It could assign a URI that tells you the status of the document (location in queue) and you can DELETE it if you no longer want to print the document.
Version in the URL requires them to update the URLs everywhere. Version in the accept header is likely a one line change somewhere.
Take HATEOAS for example; a completely academic waste of time. Writing a tiny bit of API documentation isn't hard. Caching is an awful thing to be designing in without knowing the specific application. Verbs are a hack bolted on to make hideous form/link driven applications work when the user reloads or moves back/forward.
You don't, of course, but it's usually a pretty reasonable assumption that the effort involved in implementing your own (reliable stream sockets|scheduler and memory manager|high level language compiler) will eclipse severalfold any advantage from doing so. If you don't find that the same obtains from using HTTP and hypermedia then that's your position and you're welcome to it, but don't go assuming your experience is universal.
Wrong. I implement network protocols for a living, and I use often use UDP because TCP is not sufficient for the purpose. So yeah, this is the problem: your conceit that your upfront design is going to be "enough" for everything.
In either case, I'm done here.
For example: indexing
You're going to need something that solves the problems HATEOAS solves when it comes to multi-service coordination.
curl https://api.twilio.com/2010-04-01/Accounts -H "Accept: application/json
inside a browser on a normal GET request?
Fortunately until they do, broadly, a browser user will always want the newest resource, and the type can usually be defaulted (you're using a browser, so you want HTML by default where available). Additionally, XHR and related technologies usually allow adding custom headers.
To me this is vital. Being able to explore an api within an browser makes it exponentially easier to understand and use.
Varying your content based on mobile User-Agent (or any User-Agent actually) renders public caches almost impossible to get right.
Interesting. What would you recommend doing instead, supposing, for example, that you are meant to be returning a different set of items depending on a device identifier, and that you have to support 100s of devices? Should this be considered a different resource instead of a different representation?
Also, can you point me to a nice resource about public caches?
Thanks!
On his mobile example, it's much easier to simply be pragmatic and serve content for different devices at differents URIs/domains altogether. It doesn't break if you can follow some kind of convention, such that the URLs from one map directly to the other (for instance, mysite.com/news/article -> m.mysite.com/news/article) and then you issue redirects accordingly.
David Zülke has a very good talk about REST that he's holding at conferences around the world regularly: http://www.slideshare.net/Wombert/designing-http-interfaces-....
It is a good presentation and hits on many good points but also makes the REST model a little too narrow for most client/consumer usage today easily.
http://blog.apigee.com/detail/slides_for_restful_api_design_...
nav { prev: '...', next: '....'}
in the response. But, the thing that always concerns me about this is that it requires the client to maintain state. If you consume such a web service in a web app, and the user hits "next", you'll have to have stored the next url somewhere.Personally, I'd just use a closure and bind it immediately to the event handler of the UI element.
He has the perfect anti-example for HATEOAS right in there: financial transactions. You would never in 1 million years want to discover the API for such a thing by experimentation, because there are specific precision requirements.
Every time someone tries to explain the benefits of this nonsense to me it's either 1) something you could already do with sockets 20+ years ago, or 2) a poorly motivated academic idea that doesn't get me closer to implementing a correct system with good documentation.