Wednesday, February 25, 2009

Webmachine at Erlang Factory

I will be speaking at Erlang Factory Bay Area 09 on Webmachine.

I'm looking forward to the conference; it seems like there will be a very interesting crowd.

Friday, February 6, 2009

content-negotiation for humans

Simon Willison asked for opinions on how to deliver JSON content properly while also assisting browser-driven exploration and debugging.

Here is a short, simple example of how to use content-negotiation to achieve this.

This is a complete, working webmachine resource with trivial content:


-module(conneg_demo_resource).
-export([init/1, to_json/2, content_types_provided/2]).

-include_lib("webmachine/include/webmachine.hrl").

init([]) -> {ok, x}.

to_json(_,X) -> {"{\"key\": \"value\"}\n", X}.

content_types_provided(_,X) ->
{[{"application/json", to_json},{"text/plain", to_json}], X}.


A typical request/response, with a tiny bit of header noise trimmed:


$ curl -v http://localhost:8000/js/simonw
> GET /js/simonw HTTP/1.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Vary: Accept
< Server: MochiWeb/1.1 WebMachine/0.20 (There was kicking.)
< Content-Type: application/json
< Content-Length: 17
<
{"key": "value"}


This is what you generally want. The JSON was delivered with the proper content-type and so on. Note the presence of the "Vary" header.

However, if the same request is made with a typical browser's Accept header, like FireFox's, the result will be different:


> GET /js/simonw HTTP/1.1
> Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
>
< HTTP/1.1 200 OK
< Vary: Accept
< Server: MochiWeb/1.1 WebMachine/0.20 (There was kicking.)
< Content-Type: text/plain
< Content-Length: 17
<
{"key": "value"}


This time we got the same JSON content, but in text/plain so it will display nicely in a browser window if requested directly. A Web application loading this content would probably set the Accept header in XHR requests to "Accept: application/json" and get the first response.

This is a straightforward use of content-negotiation that serves a useful purpose and (by using Accept properly and providing the Vary response header) still works well with intermediaries and the rest of the mechanics of the Web.