views:

199

answers:

4

Since I can't find a chuffing job, I've been reading up on ReST and creating web services. The way I've interpreted it, the future is all about creating a web service for all your data before you build the web app. Which seems like a good idea.

However, there seems to be a lot of contradictory thoughts on what the best scheme is for ReSTful URLs.

Some people advocate simple pretty urls

http://api.myapp.com/resource/1

In addition, some people like to add the API version to the url like so

http://api.myapp.com/v1/resource/1

And to make things even more confusing, some people advocate adding the content-type to get requests

http://api.myapp.com/v1/resource/1.xml
http://api.myapp.com/v1/resource/1.json
http://api.myapp.com/v1/resource/1.txt

Whereas others think the content-type should be sent in the HTTP header.

Soooooooo.... That's a lot of variation, which has left me unsure of what the best URL scheme is. I personally see the merits of the most comprehensive URL that includes a version number, resource locator and content-type, but I'm new to this so I could be wrong.

On the other hand, you could argue that you should do "whatever works best for you". But that doesn't really fit with the ReST mentality as far as I can tell since the aim is to have a standard.

And since a lot of you people will have more experience than me with ReST, I thought I'd ask for some guidance. So, with all that in mind...

What should the standard be for ReSTful URLS?

+3  A: 

The verb cannot be put into the URL. That makes no sense. It's already in the request header. When you send a POST request that has GET in the URL, that's crazy.

The response format is usually best put into the URL because the headers don't provide a simple, unambiguous place to put that information.

S.Lott
you're right, I misread this article and took it at face value http://microformats.org/wiki/rest/urls
gargantaun
+1  A: 

I'm with S.Lott -- the Verb *should not* be in there, as you want to use the same URL for reading the record as for updating it for it to qualify as REST.

The content-type is something else to leave out, as it's the same record, but with multiple encoding formats. (Read up on FRBR for way more than you ever wanted to know about the issues of the distinction). The decision of which version to send in response can be handled with HTTP Accept headers.

The only one that I'm torn on is the version number, as I can't personally think of an appropriate HTTP header to handle that aspect of it. (Expect? Accept-Encoding? Pragma? Maybe even Upgrade, but you'd more frequently want to downgrade to an older version for compatibility reasons, I'd think) I'd probably have a version-less accessor which gave the most recent production version, but might consider have a version'd one for significant changes that weren't backwards-compatible.

update: the version issue probably depends on how much control you have over the clients connecting to your services ... if you have access from a wide public (which I don't), you might be more interested in backwards compatibility. Depending on the changes made, it's possible that you might also consider 'version 2' to be a completely new resource, rather than just a new 'version' of the original.

Joe
wouldn't having an optional version number make mod_rewrite and routing more difficult? Also, by having the version number in there, it would be easier for people to upgrade and downgrade by having the required api version in a boot strap, rather than having to change each request by hand.
gargantaun
Content-type is the header you would use if want your server to be able to deliver two different versions of a representation. e.g. application/vnd.twitter.statusesV1+xml and application/vnd.twitter.statusesV2+xml Using this approach the client can request the version that they understand and new versions can be introduced without breaking clients. Obviously, the media-type should be designed in the first place to be as resilient to change as possible and introducing a new version number should only be last resort when it would break old clients.
Darrel Miller
Darrel -- the HTTP 'Accept' header is what the client would use to specify what types they're willing consume, and then the server would either respond (setting Content-type as appropriate) or with a status of 406 (Not Acceptable)
Joe
@joe Oops, my mistake. You are correct.
Darrel Miller
@joe Take a look at this http://www.infoq.com/presentations/restful-financial-systems-integration video. The presenter shares experiences in a "small" financial services company where they used REST to integrate a number of different systems. One of the reasons that versioning by content-type was important to them was because it allows department A to be able to make changes to their output to serve department C without having to convince department B to make changes to their existing system.
Darrel Miller
+2  A: 

Versioning: I've usually seen this placed where you have it in your example url, and if a version isn't specified you should respond with the most recent production version. One consideration is whether to put the API version in your response string for client debugging purposes.

Response formats: The return format should be specified in the HTTP Accept header sent by the user agent.

Verbs in the request string: Absolutely not.

Nicholas
Is there not an argument for usability. The URL is part of the user interface if the service is being accessed through a browser. So while it should be in the HTTP Accept header, there could be a benefit by also having it in the url.
gargantaun
In that case, I think the real usability issue comes when you have JSON in the accept header and XML in the url.
Nicholas
If you're taking an older API and adding a new version (where no version parameter was previously specified), then I'd suggest that, if a request is received without a version parameter, you respond with the oldest version of your API instead of the newest; otherwise, you'll break older clients. If this type of "most-recent" behavior had been specified since V1 of the API, however, then it'd be okay. My two cents.
Nicholas Piasecki
+4  A: 

Welcome to the confusing world of what is and what is not REST. First I would suggest that you have been reading about REST in the wrong places. Try RESTWiki as a good starting point.

REST is not a great solution for delivering data services for your web app. "Web Services" (aka SOAP, XML-RPC, WSDL, HTTP-POX) may be good for that but the REST architectural style is much more oriented towards client-server scenarios than server-server scenarios.

Stop thinking about what URLs look like. What they look like has much more to do with which server side framework you use to implement the RESTful service than the design of the service itself. The client should discover URLs from previously retrieved representations, so it really does not care what the URLs look like.

Having said that, using your example URLs to try and distinguish what you believe should be different resources, I do have some other suggestions.

Don't version resources. i.e. if you have a resource that is accessed by the url http://example.org/TodaysWeather don't ever create a resource at http://example.org/V2/TodaysWeather. There are lots of other better ways to version representations than creating a whole new resource. Search SO for lots of other discussions on this.

As for creating different resources for different content-types, I believe that is a context specific decision. If your end-user is using a browser to access the REST service and they are sophisticated enough to understand the difference between JSON and XML then go ahead and create two resources. If it is a machine client then I would use content negotiation to get the required format.

And finally, be careful out there, since REST became a buzzword du jour, there is far more mis-informed content around than there is valid content.

Darrel Miller
Much of it is subjective, I think. Semantically, not explicitly versioning particular resources makes sense, unless that's an actual part of the business problem (i.e., I want to view my InsuranceCoverage resource as it was two years ago, not right now). But I would submit that shoving a "v1" at the beginning of the URL makes it explicit what version of the API you're talking with. You can also imagine how the server's code would be tidy, too--V1 code is untouched when V2 is created because those are all new classes, no need to insert a switch statement on a Version header in the request.
Nicholas Piasecki
When most people talk about versioning they are not referring to "business relevant" versions. You are right though, if it is business relevant then making it a different resource makes sense.Adding versions to URIs gets really messy when you use hypermedia properly and only part of your API needs a new version. Now you have representations that are accessed with V2 urls that point to resources from the V1 api.
Darrel Miller
As for being tidy on the server side, versioning media types can be just as easy to separate. Generally there already exists a mechanism to "switch" on content-type, so adding a version to the content-type just reuses that mechanism for delivering the right version.
Darrel Miller
Why do you feel REST isn't a great solution for server-server scenarios? Why are other web service stacks better?
Marcus
@Marcusa) Server to server solutions more frequently require transactions that REST does not support.b) Hypermedia makes much more sense when driven directly by a human. REST is all about reducing coupling. If you control both servers in a data center, then reducing the coupling between them is much less significant than in other scenarios.
Darrel Miller
Couldn't agree more with your point Darrel - there's a lot of confusion about where the adjective RESTful makes sense. There is nothing REStful about the URIs themselves. Agree on the other parts, too. +1
Milan Novota