Prototype.js, JSON and Catalyst
From Dev411: The Code Wiki
The latest versions of the Prototype.js AJAX library support auto-eval of JSON objects if they are located in the X-JSON header. JSON is useful for minimizing the number of requests and has lower overhead than XML. This page shows how to read the json object in a Ajax.Request response and how to set it using Catalyst and JSON::Syck. I believe prototype.js 1.4.0 and higher is necessary to get prototype's JSON auto-eval feature. This is tested with prototype.js 1.5.0 rc0, Catalyst 5.6902 and JSON::Syck 0.12. The prototype website currently supplies prototype.js 1.4.0 while 1.5.0 rc0 is available with Scriptaculous.
Prototype.js and JSON
Prototype will automatically eval the JSON response if it is placed in the X-JSON header. In the JavaScript you can access the JSON object using the following where myItem is defined in the JSON response:
new Ajax.Request(
ajax_uri, {
asynchronous:1,
onComplete: function(request,json) {
alert(json.myItem);
}
}
);
Catalyst and JSON::Syck
I use Catalyst as my server-side MVC framework and Catalyst::Response to set the X-JSON header. To create the JSON string, I use JSON::Syck which is a Perl wrapper for the fast C libsyck library. Catalyst::View::JSON is available on CPAN, however, it places the JSON object in the response body which is fine for other libraries such as Dojo but it does not support the X-JSON header prototype uses. Unfortunately there's no standard way to auto-detect the type of AJAX library being used so some other method may need to be used, e.g. a config parameter. In any event, here's an example for using JSON::Syck directly with Catalyst::Response:
package MyApp::Controller::Ajax;
use JSON::Syck;
sub test_json : Local { # in a Controller
my ($self,$c) = @_;
my %data = ( myItem => 'hello world' );
my $json = JSON::Syck::Dump( \%data );
$c->res->header( 'X-JSON' => $json );
}
IE Max Header Length and Manual Eval
While Firefox can accept HTTP headers of arbitrary length, IE 6 seems to have a max length under 2000 bytes. Exceeding the max header length will cause prototype's JSON eval to silently fail. Dojo and other libraries read the JSON object out of the response body which does not have a max length. For now I'm going to return the prototype JSON object in the response body and manually eval which is compatible with Catalyst::View::JSON.
To eval in the Javascript, simply eval the responseText. Here's an example:
evalResponse = function(request) {
try {
return eval('('+request.responseText+')');
} catch (e) {}
}
new Ajax.Request(
ajax_uri, {
asynchronous:1,
onComplete: function(request) {
var json = evalResponse(request);
alert(json.myItem);
}
}
);
