eriksmartt.com>Selected Archives

Passing JSON via the X-JSON HTTP header with Django and Prototype

One of the demo sites I was working on this week needed to pass a small amount of JSON back with it's page results. There are better to do this (and I'd suggest this post, "Loading Content with JSON" as a starting point if you're looking for ideas) but for simplicity, I decided to take advantage of the automatic X-JSON HTTP Header parsing feature in Prototype 1.5.0. (The Ajax.Request docs address this capability.)

The sample code below demonstrates the use of the X-JSON header with an simple "sticky notes" web app. On the client-side, the JavaScript is quite simple. The second variable in the onSuccess callback handler will be automatically initialized using the data in the X-JSON header:

function display_note(id) {
    new Ajax.Request('/api/note/' + id + '/', {
        method: 'get',
        onSuccess: function(transport, results) {
            alert("Note(" + results['id'] + ") `" + results['title'] + "`: " + results['body']);
        },
    });
}

To handle this request, I'm using Django on the server with the following URL pattern:

(r'^api/note/(?P<id>\d+)/$', 'views.get_note')

The get_note method implementation looks like this: [NOTE: For production use, you'll want some exception handling, but I removed the error handling to simplify the example.]

def get_note(request, id):
    # Fetch the Note from the DB:
    note = Note.objects.get(pk=id)
    # Create the response object (with some dummy text for now):
    response = HttpResponse('Check the X-JSON header.')
    # Manually set the X-JSON header using the JSON generated from the Note record:
    response['X-JSON'] = cjson.encode(note.__dict__)
    # Return the response object:
    return response

If you'd like to use this technique on your own sites, there are couple points to remember:

  1. You can't return an empty HTTP Response regardless of there being an X-JSON header. If the response is empty, the browser will hang waiting for content to arrive.
  2. The X-JSON header should only be used for small payloads. Don't stuff more then 8kb in your headers. If you're sending more then that, move the JSON to the body of the response.
  3. The cjson and simplejson encoders don't handle Django DateTime fields. For objects with DateTime fields, write an alternate method for converting the object into a dictionary before passing it to the json encoder.

[Update: 2009/04/10] This post got some flak for demonstrating a technique of pushing JSON out that might slip past some security checks. That in itself is intresting, but I do want to point out that you likely don't want to use HTTP Headers to pass this kind of data in a production site anyway. You'll find out quickly that there are character limits to how much you can put in the headers, and before long, the distinction between what data goes in the header and what goes in the body will blur. Once that happens you've got a big mess on your hands. Better would be to avoid this pattern all together. My post here simply demonstrates how to use the technique, should you be interested in doing so.