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