Teach your XMLHttpRequest some JSON

I recently started to use JSON for the data exchange between websites and servers (Yeah, I know I’m late ;)) and was looking for a lightweight solution to send HTTP requests carrying JSON encoded data via JavaScript. The best idea I’ve found was the JSONRequest proposal on json.org, but this has two essential flaws: browser support is not really existent and it doesn’t allow RESTful communication.

So I stuck with the native XMLHttpRequest object and extended it’s functionality. The compressed code is just 822 Bytes and XMLHttpRequest compatible. You’re even able to send cross-domain-requests with a bit extra code (see my AJAX cross domain requests with CORS post for more). The code is reported to work with IE9, FF7, Chrome 16, Safari 5.1 and Opera 11.60 beta, but I’m pretty sure every browser with JSON and XMLHttpRequest support should work (tell me whether it works with your browser or not).

You might want to visit my little example page to test the whole thing right away, but I suggest to read a least the section about how to use the JSONHttpRequest object, before you download the code to use it in your page.

How to use the JSONHttpRequest

The JSONHttpRequest is a transparent extension of the standard XMLHttpRequest object. This means you can use all of its methods and properties defined in the W3C specification as well as any browser-specific additions. The difference between a normal XMLHttpRequest and a JSONHttpRequest are just two new properties and one new method:

  • sendJSON(data): converts any data to JSON and sends them via send(data)
  • responseJSON: responseText interpreted as JSON or null
  • strictJSON: whether JSON errors should throw an exception (default: true)

Calling sendJSON() will set the content-type to application/json;charset=encoding, if you haven’t set another value via setRequestHeader('Content-Type', value). encoding will be UTF8 in most cases. Everything else should be pretty straight forward, but let me know if you need more details.

Understanding the code

A look on the overall size and the number of additions implies that the code couldn’t be too complicated, but the XMLHttpRequest object seems to be a bit different that normal objects in some browsers. Especially prototyping won’t work, therefore the following code

JSONHttpRequest = new Function();
JSONHttpRequest.prototype = new XMLHttpRequest();
request = new JSONHttpRequest();
request.open('POST','page.html');

results for the IE in an invalid calling object, for Opera in a WRONG_THIS_ERR and for Safari in a TypeError exception. I fiddled around with __proto__ and getPrototypeOf(), but even that didn’t solve all issues, so I finally went another way.

In the end I used the JSONHttpRequest as a container for a XMLHttpRequest object, which is only visible within the closure (it’s more or less a private property). All methods of the XMLHttpRequest are accessible via some – dunno a better name – proxy methods:

this.open = function() {
  return _xmlHttpRequest.open.apply(_xmlHttpRequest, Array.prototype.slice.apply(arguments));
}

Sebastiano Armeli explained this whole apply-slice-arguments thing quite nicely in his blog, so I won’t do double work here ;) Instead I’ll continue with the properties, which are accessible in a similar way like the methods using getters and setters:

Object.defineProperty(this, 'onreadystatechange', {
  get: function() { return _xmlHttpRequest.onreadystatechange; },
  set: function(value) { _xmlHttpRequest.onreadystatechange = value; },
  enumerable: true,
  configurable: true
});

The actual implementation uses a for-loop, which runs over all enumerable properties of XMLHttpRequest, to set up the whole proxy stuff. This is done mainly to shrink the size of the code, but the idea is the same as sketched here. I think the rest of the code shouldn’t be too cryptic (even though I chose compressor friendly code over readability), but feel free to ask if anything is still unclear.

The famous last paragraph

Here are the example and download links once again. I hope my work is of some use for someone. Everything is open-source so don’t hesitate to improve anything and please tell me if you know a better solution to this problem. Happy coding :)

7 thoughts on “Teach your XMLHttpRequest some JSON”

  1. Are you sure this method can do the cross-domain JSON post? if so what ‘s the point of this CORS implementaion: https://bitbucket.org/jsumners/corsfilter/overview. or they have to combine together. Yours is for client side, another is for server side. Please clarify. Thanks

    1. Yeah, you’re right: My code here is pure client-side stuff. It only de/encodes JSON data on the fly, which makes JSON-based communication with a server a bit easier.

      As any other AJAX-request object you can use JSONHttpRequest in combination with CORS to communicate with a server outside of your domain, but that needs additional handling on the client- and server-side. You might want to read my AJAX cross domain requests with CORS post, if you want to know more about it.

      PS: I’ve edited my post a bit to make this point clearer. Thanks for the hint :)

  2. “Teach your XMLHttpRequest some JSON”

    Broken links for the pages in example and download

    Great tut. Please provide the links again.

    K.

    1. Thanks for the hint! It seems that I’ve misconfigured something when I moved Pixels vs. Bytes to a new server. Everything is working now again :)

  3. Hi Torben.. I am facing the error here.. I have followed the code and replace the XMLHttpRequest as JSONHttpRequest and put the JSON.parse() function at the return_data = hr.responseText but when i run my page, it shows the error “Unexpected token document.getElementById(“statusUpdate”).innerHTML = “” + return_data + “”; but i have comment it.. still the error appears at my console..

    1. Hi Irfan,

      it’s difficult to debug, when I can’t see the code. Can you give me an URL or something? Apart from that I thing you might have get the usage wrong. The point of JSONHttpRequest is that you don’t have to use var return_data = JSON.parse(hr.responseText); but var return_data = hr.responseJSON; instead.

      However, I’m not sure whether your bug is really caused by my JSONHttpRequest code or not. To test that I would suggest to remove all JSONHttpRequest stuff from your code and use JSON.parse(hr.responseText) instead. If the problem still occurs it’s not caused by my code. Otherwise I’m happy to help if you can give me an URL to your code.

Leave a Reply to Torben Cancel reply

Your email address will not be published. Required fields are marked *