Catalyst-View-JSON
view release on metacpan or search on metacpan
value (euc-jp in this case) before emitting the data to the browser.
Another option would be to use *JavaScript-UCS* as an encoding (and pass
Unicode flagged string to the stash). That way all non-ASCII characters
in the output JSON will be automatically encoded to JavaScript Unicode
encoding like *\uXXXX*. You have to install Encode::JavaScript::UCS to
use the encoding.
CALLBACKS
By default it returns raw JSON data so your JavaScript app can deal with
using XMLHttpRequest calls. Adding callbacks (JSONP) to the API gives
more flexibility to the end users of the API: overcome the cross-domain
restrictions of XMLHttpRequest. It can be done by appending *script*
node with dynamic DOM manipulation, and associate callback handler to
the returned data.
For example, suppose you have the following code.
sub end : Private {
my($self, $c) = @_;
if ($c->req->param('output') eq 'json') {
$c->forward('View::JSON');
} else {
...
}
}
"/foo/bar?output=json" will just return the data set in "$c->stash" as
JSON format, like:
{ result: "foo", message: "Hello" }
but "/foo/bar?output=json&callback=handle_result" will give you:
handle_result({ result: "foo", message: "Hello" });
and you can write a custom "handle_result" function to handle the
returned data asynchronously.
The valid characters you can use in the callback function are
[a-zA-Z0-9\.\_\[\]]
but you can customize the behaviour by overriding the
"validate_callback_param" method in your View::JSON class.
See <http://developer.yahoo.net/common/json.html> and
<http://ajaxian.com/archives/jsonp-json-with-padding> for more about
JSONP.
NOTE For another way to enable JSONP in your application take a look at
Plack::Middleware::JSONP
INTEROPERABILITY
JSON use is still developing and has not been standardized. This section
provides some notes on various libraries.
Dojo Toolkit: Setting dojo.io.bind's mimetype to 'text/json' in the
JavaScript request will instruct dojo.io.bind to expect JSON data in the
response body and auto-eval it. Dojo ignores the server response
Content-Type. This works transparently with Catalyst::View::JSON.
Prototype.js: prototype.js will auto-eval JSON data that is returned in
the custom X-JSON header. The reason given for this is to allow a
separate HTML fragment in the response body, however this of limited use
because IE 6 has a max header length that will cause the JSON evaluation
to silently fail when reached. The recommend approach is to use
Catalyst::View::JSON which will JSON format all the response data and
return it in the response body.
In at least prototype 1.5.0 rc0 and above, prototype.js will send the
X-Prototype-Version header. If this is encountered, a JavaScript eval
will be returned in the X-JSON response header to automatically eval the
response body, unless you set *no_x_json_header* to 1. If your version
of prototype does not send this header, you can manually eval the
response body using the following JavaScript:
evalJSON: function(request) {
try {
return eval('(' + request.responseText + ')');
} catch (e) {}
}
// elsewhere
var json = this.evalJSON(request);
NOTE The above comments were written a number of years ago and I would
take then with a grain of salt so to speak. For now I will leave them in
place but not sure they are meaningful in 2015.
SECURITY CONSIDERATION
Catalyst::View::JSON makes the data available as a (sort of) JavaScript
to the client, so you might want to be careful about the security of
your data.
Use callbacks only for public data
When you enable callbacks (JSONP) by setting "allow_callback", all your
JSON data will be available cross-site. This means embedding private
data of logged-in user to JSON is considered bad.
# MyApp.yaml
View::JSON:
allow_callback: 1
sub foo : Local {
my($self, $c) = @_;
$c->stash->{address} = $c->user->street_address; # BAD
$c->forward('View::JSON');
}
If you want to enable callbacks in a controller (for public API) and
disable in another, you need to create two different View classes, like
MyApp::View::JSON and MyApp::View::JSONP, because "allow_callback" is a
static configuration of the View::JSON class.
See <http://ajaxian.com/archives/gmail-csrf-security-flaw> for more.
Avoid valid cross-site JSON requests
Even if you disable the callbacks, the nature of JavaScript still has a
possibility to access private JSON data cross-site, by overriding Array
constructor "[]".
( run in 0.599 second using v1.01-cache-2.11-cpan-39bf76dae61 )