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. Please subscribe to the RSS feed and remember that future readers will thank you for leaving your comments and criticisms. Subscribe to RSS Feed

Comments (8)

March 15th 2012

donkikong said:

Those asking about OPTIONS should have a look at this article on the same origin policy: http://en.wikipedia.org/wiki/Same_origin_policy In short: you cannot make an asynchronous request outside of the domain that you are requesting from, so if you're trying to test from a local file, this will fail. Try using JSONP with a callback.

February 27th 2012

Dobes said:

OPTIONS is related to a new cross-domain features being added to modern browsers. https://developer.mozilla.org/en/http_access_control

February 16th 2012

jquerier said:

Sending OPTIONS instead of POST seems to be a jQuery/Firefox/cross-domain bug. I can't help you beyond that since I can't reproduce it myself. http://stackoverflow.com/questions/1099787/jquery-ajax-post-sending-options-as-request-method-in-firefox

January 19th 2012

Khurram Rahe said:

Hi, I also got the same problem, why in the nodejs, when i'm sending the post to the server, request.method is returning "OPTIONS" instead of "POST" . Feeling very confusing

December 23rd 2011

Rob said:

Hi there I am running into a crossdomain issue when communicating through POST on the above method, is there something obvious I am missing? - Mobile app communicating using POST on an Ajax call, sending data across to the server and expecting a callback. - Server has node setup with a app.post('/blah') and that does a res.send... This works fine if the call is made off the same server but when it's outside the domain that fails. Any ideas? Thanks!

December 22nd 2011

node.bs said:

i'm not convinced about this entire paradigm.. i beleive in JSON as the transport structure, and i believe in JS / jQuery on the client side.. however, i'm pretty sure i can see this technology being used as a very light chat / real time applicatoin HELPER. Most of the data is static, some of the "DATA" needs to be refreshed often, and only then does it make sense to pump it out with node.js. I think IISNode port may have some practical applications.. and maybe i'm wrong, i've just seen a lot of these things come and go.. however, i'd say from the OS community.. this is something to keep them trying

December 16th 2011

Mcloud said:

Hi, I got problem, why in the nodejs, when i'm sending the post to the server, request.method is returning "OPTIONS" instead of "POST" thank you for your help

March 28th 2011

Vidar said:

I'm excited too, this is the future! Thanks for the writeup.

Leave a Comment

Your Name:
Comment:
Enter this phrase:
captcha