4

Assume I have a RESTful web service, which holds information about an object that can be accessed at an url like http://example.com/myobject. I would like to be able to retrieve this information in two formats: firstly, the XML-formatted plain data, and secondly, as a full HTML page, which may also include a javascript interface to change the object and PUT it back with AJAX.

What is the canonical way to achieve this? Should I publish my object at two different urls like http://example.com/myobject?format=xml and ...format=html? (Are there better ways than using a query string to distinguish the URLS here?) Or is it sensible to send something like multipart MIME data and can I rely on browsers being able to extract the HTML part? Or is there some HTTP header field in the request I could use?

(With PUT or POST requests sent in different formats, it is much easier as the server can check the format and parse it accordingly.)

Marc
  • 4,327
  • 4
  • 30
  • 46

3 Answers3

5

You could alternatively use content negotiation instead of querystring parameters. In a nutshell, the client sends the acceptable media types via the Accept header in the request (e.g. "application/xml, text/html;q=0.9"), and the server analyzes this and replies with the client-preferred media type (this process is called server-driven negotiation)

When doing server-driven negotiation, the response should contain a Vary header indicating what request header was used in the negotiation

Keep in mind that for this to work the client must send an appropriate Accept header.

Mauricio Scheffer
  • 98,863
  • 23
  • 192
  • 275
  • Thanks for the tip with the Accept header. Now I have been reading how browsers set the accept header. The only remaining problem seems to be that browsers seem to put many mime types in the Accept header. However, text/html seems to be always be requested with q=1, which makes it somewhat reliable. – Marc Jun 11 '11 at 21:59
  • @Marc: you'd be surprised. Chrome (version < 12) still preferred application/xml over text/html, and I think other webkit-based browsers too. IE used to send (version < 9) all kinds of sh*t in the Accept header. And most people are still using these older browsers. – Mauricio Scheffer Jun 11 '11 at 22:33
  • 1
    Here's a small survey of browser Accept headers (feel free to add more): https://spreadsheets.google.com/spreadsheet/ccc?key=tF4FAJK-lb08wflsbk--A8A#gid=0 – Mauricio Scheffer Jun 11 '11 at 23:07
  • See also: http://stackoverflow.com/questions/6229503/what-are-the-pros-and-cons-of-using-uri-vs-accept-headers-for-rest-content-format – Mauricio Scheffer Jun 12 '11 at 04:24
3

A way which happens to be very easily readable, is to just use the extension:

http://example.com/myobject.html
http://example.com/myobject.xml
http://example.com/myobject.json
etc.

Otherwise you could use the request's accepted content type, which you can find in the request header, e.g. text/html for HTML, text/xml for XML, text/json for JSON, and so on. This is called Content Negotiation:

Content negotiation is a mechanism defined in the HTTP specification that makes it possible to serve different versions of a document (or more generally, a resource) at the same URI, so that user agents can specify which version fit their capabilities the best.

That would leave your URLs very simple and you would deliver HTML output when nothing else is specified (and the page is accessed through the browser).

slhck
  • 36,575
  • 28
  • 148
  • 201
  • Using suffixes seems to be the easiest way but wouldn't it contradict one RESTful principle, namely that the URL should point to a resource and not to a way to output it? (I know that my "...?format=xml" idea isn't better in this regard...) – Marc Jun 11 '11 at 22:01
  • Yes, that is right of course. That's why I added the Content Negotiation thing, but @Mauricio got that too, so, you're set :) – slhck Jun 11 '11 at 22:03
  • 1
    @Marc There is nothing wrong with creating three distinct resources for the different formats. REST does not have any objection to this. The only downside is that it makes cache invalidation a bit more tricky. – Darrel Miller Jun 12 '11 at 01:56
0

You're going to find that you want one HTML page to manage a handful or more of your XML resources, not just one. So stick your HTML form at example.com/stuff and your XML resources at example.com/api/thing, object, etc. Alternately, if you want the XML to be the main navigation, stick that at example.com/things, etc and your HTML at example.com/things/manager.html or something similar. This is getting even easier now that Firefox and Chrome have plugins that allow human users to click on hyperlinks in non-HTML types.

fumanchu
  • 14,419
  • 6
  • 31
  • 36