Practical HATEOAS Part 2: Content Negotiation
In the first post about Practical HATEOAS I covered several areas of the GeekZone API that I thought were lacking a sense of purity when it comes to REST, and HATEOAS in particular.
For the first followup post I was planning to expand on the notion of resource linking, but before that lets look at giving a distinct URI to each representation of a resource. In the comments Emanuele called me to task on content negotiation, citing the O’Reilly RESTful Web Services book, page 92:
If a server provides multiple representations of a resource, how does it figure out which one the client is asking for? For instance, a press release might be put out in both English and Spanish. Which one does a given client want? There are a number of ways to figure this out within the constraints of REST. The simplest, and the one I recommend for the Resource-Oriented Architecture, is to give a distinct URI to each representation of a resource. http://www.example.com/releases/104.en could designate the English representation of the press release, and http://www.example.com/releases/104.es could designate the Spanish representation.

As a general rule, I believe a URI should only point to a single resource, unfortunately we live in a world where people think the web serves up files and filenames rather than anemic URIs and code appropriately. The above example, IMHO doesn’t talk about two representations of a single resource but rather two separate resources: the english and spanish translations of a press release.
The distinction being that if the spanish resource gets updated or deleted I would assume the english resource would remain unchanged whereas if a users email address were changed I would except to see that reflected in both an XML and JSON representation.
In fact, the HTTP specification already provides a standard method of differentiating resource translations via the Accept-Language and Content-Language headers.
GET /releases/104
Accept-Language: en
...
Content-Type: text/html
Content-Language: en
<html>...
When using the more simplistic “/releases/104.en” to specify the english translation of the resource, what format do you want it in? Or are you happy with “application/octet-stream” – everyones favorite baseline?
A valid use case for the fake filename approach to content negotiation is when you wish to save the resource to disk, and are unable to control the output filename, i.e. a Javascript web application which breaks out of its XMLHttpRequest/AJAX model to let the surrounding browser open/save an “example.pdf” resource.
A more RESTful approach, which ignores client behavior would be the combination of the above headers along with Content-Disposition – the RFC-2183 defined header for conveying presentation details:
Content-Disposition: attachment; filename=release-104-en.pdf;
The header is supported by most browsers, but as with most things – Internet Explorer has the spottiest track record when it comes actually supporting it, however on this topic I’m willing to argue that the browser is not your client – javascript is – don’t limit yourself by your clients host.
By using the fake filename approach, or more – by potentially mixing languages, and formats in that filename, you’re loosing API uniformity and consistency for the sake of being easier on dumb clients applications.