As promised, here is the RESTful JSON client I referred to previously. I am willing to bet you weren't expecting JavaScript.
Note: this has only been tested in FireFox 1.5 on Ubuntu, your mileage may vary. Here is a screenshot to refer to if the page doesn't work for you.
Here is a pretty printed version of the JavaScript , in case you haven't pull down the source code for yourself via bzr. This code only relies on one external library, MochiKit for the JSON serializer. Yes, that's heavyweight for just one small bit of functionality, but the alternative has copyright issues we don't need to rehash here again.
As for the operation of the application, there are five links, click on them and the recipe shows up in the form elements below. From there you can update or delete the recipe, or type in a new recipe and press "Create" to have it added to the list. All of this happens via calls to the JSON Server implementation I described previously.
So what, what have I done here, besides re-invent GMail, poorly? While the interface is nothing special AJAX-wise it is unique is that the back end protocol is RESTful and not RPC. Admittedly at this point it is a pretty naive implementation and there are basic optimizations that we can do now that we have a RESTful interface, for example, implementing ETags and gzip, which I will do a in a future article.
One of the things I learned from doing this implementation was the feedback it provided into the original idea for the protocol that I had outlined before. One of the things that seems akward is that the interaction with the server is pretty chatty regardless of the size of the member entry representations. One of the first things that should change is that in the case of small payloads, like our recipe, it may make sense to include the entity in the collection document. So instead of just supplying:
{
"members": [
{"href": "1"},
{"href": "2"},
{"href": "3"},
{"href": "4"}
],
"next": null
}
We could optionally include the actual member representation via an "entity" name/value pair.
{
"members": [
{"href": "1",
"entity", {
"instructions": "First, get a trout...",
"id": 1,
"title": "Trout on a stick"
}
},
...
],
"next": null
}
That could help reduce the number of requests to member resources when populating a list, like we do when the cookbook page starts.
But we could even take that optimization one step further, because we really should do a GET every time the user clicks on a link to make sure the latest version of the recipe is presented. Having the entity in the collection document doesn't really give us anything in that case since we don't know if the verson on the client is stale. One thing we could do is include the ETag for each member resource in the collection document. That would allow us to do a conditional GET on the member the first time the user clicked on the link and if the member was unchanged we would get a 304 Not Modified response and no entity body, which is potentially much fast than doing a non-conditional GET.
Let's revise our collection document one more time to reflect those ideas:
{
"members": [
{"href": "1",
"etag":"0hf0239hf2hf9fds09sadfo90ua093j",
"entity", {
"instructions": "First, get a trout...",
"id": 1,
"title": "Trout on a stick"
}
},
...
],
"next": null
}
Note that both "etag" and "entity" should be optional.
This is looking pretty good, the initial idea was easy to implement on both the client and the server and the first implementations have provided some good feedback on the structure of the protcol. I think I ought to say a bit more on where I think this overlaps with the Atom Publishing Protocol and also maybe write up the protocol more formally, all of which I will do in future entries.