JSON Round Trip with node.js colorful lead photo

I've been playing around with node.js a lot recently, because, well, server-side JavaScript is the future of web development, at least for rich internet applications. Basically, if your project uses a lot of JavaScript on the client and primarily uses AJAX and JSON to communicate with the server, then the parsimony, code reuse, and low impedance mismatch of also using JavaScript on the server mean that you'll be at least twice as fast as teams that have to deal with two languages, write separate utilities for the server and client, and massage messages to work in both languages.

One of the first things you need to do, if you're serious about writing a RIA with a JavaScript backend, is be able to quickly send messages to and from the server. JSON is obviously the best format for JavaScript-to-JavaScript communication. So, I set up a simple example of a node.js server that can both send and receive JSON objects via AJAX, and cache them in memory on the server. The full code of the example is out on github:

I'm going to pluck out the juicy bits right here, though, and explain them.

Client To Server

The first thing you need to do is be able to POST a JSON object. This is easy enough with jQuery:

function put(id, data, callback) {
    $.ajax('http://127.0.0.1:8181/' + id + '/', {
        type: 'POST',
        data: JSON.stringify(data),
        contentType: 'text/json',
        success: function() { if ( callback ) callback(true); },
        error  : function() { if ( callback ) callback(false); }
    });
}

Note that the body of the POST is not URL encoded, like that of a POSTed form: that's verbose and wasteful, and gets us nothing since we'd have to decode it on the server anyway. Note also that I'm using JSON.stringify. This is in the ECMA-262 standard, built into modern browsers, and Douglas Crockford has written a JSON compatibility library for legacy browsers.

The next step is to receive that message on the server. Inside of a HTTP response handler:

http.createServer(function(request, response) {
    ...
    if ( request.method === 'POST' ) {
        // the body of the POST is JSON payload.
        var data = '';
        request.addListener('data', function(chunk) { data += chunk; });
        request.addListener('end', function() {
            store[id] = JSON.parse(data);
            response.writeHead(200, {'content-type': 'text/plain' });
            response.end()
        });
    }
    ...
}

The request is emitting multiple "data" events, each with a piece of the JSON string: we have to accumulate all of these into one string. When all data is received, the "end" event is emitted, and we can proceed to parse the now-complete JSON string. In this case our handling consists only of tucking away the deserialized object in the store. Afterwards, we return a empty document with a "200 OK" status.

I should probably do error handling on the JSON.parse as it's likely to throw an exception, but I forgot. Typical error handling looks like this:

try {
    store[id] = JSON.parse(data);
} catch ( e ) {
    response.writeHead(500, {'content-type': 'text/plain' });
    response.write('ERROR:' + e);
    response.end('\n');
}

Server To Client

This is very simple. On the server, we just have to get the object out of the store, serialize it, and write it out.

if ( request.method === 'GET' ) {
    // exact id lookup.
    if ( id in store ) {
        response.writeHead(200, {'content-type': 'text/json' });
        response.write( JSON.stringify(store[id]) );
        response.end('\n');
    } else {
        response.writeHead(404, {'content-type': 'text/plain' });
        response.write('no data for ' + id);
        response.end('\n');
    }
}

Note that I'm using the mime type text/json. The official MIME type is application/json, but I've had trouble with frameworks treating that as unencoded binary data. You should probably use the standard, though, unless you have a good reason.

jQuery supports JSON data right out of the box, so there's barely anything for us to do on the client:

function get(id, callback) {
    $.ajax('http://127.0.0.1:8181/' + id + '/', {
        type: 'GET',
        dataType: 'json',
        success: function(data) { if ( callback ) callback(data); },
        error  : function()     { if ( callback ) callback(null); }
    });
}

Conclusion

It's easy to send JSON from the client to the server, and even easier to get it from the server to the client. There are no no mismatched data types, no parsing or serialization algorithms, just two environments that speak the same language communicating in a minimal (but not trivial) subset of that language. Can you see why I'm so excited about this stuff?

- Oran Looney March 9th 2011

Thanks for reading. This blog is in "archive" mode and comments and RSS feed are disabled. We appologize for the inconvenience.