Theory In Practice

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.

If Javascript is your client platform - coding the server to Internet Explorers limitations is stupid. The browser is NOT your client.

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.

Recent comments

Blog comments powered by Disqus