Catalyst-View-JSON

 view release on metacpan or  search on metacpan

lib/Catalyst/View/JSON.pm  view on Meta::CPAN

Another option would be to use I<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 I<\uXXXX>. You have to install
L<Encode::JavaScript::UCS> to use the encoding.

=head1 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 I<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 {
          ...
      }
  }

C</foo/bar?output=json> will just return the data set in
C<< $c->stash >> as JSON format, like:

  { result: "foo", message: "Hello" }

but C</foo/bar?output=json&callback=handle_result> will give you:

  handle_result({ result: "foo", message: "Hello" });

and you can write a custom C<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
C<validate_callback_param> method in your View::JSON class.

See L<http://developer.yahoo.net/common/json.html> and
L<http://ajaxian.com/archives/jsonp-json-with-padding> for more about
JSONP.

B<NOTE> For another way to enable JSONP in your application take a look
at L<Plack::Middleware::JSONP>

=head1 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 I<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);

B<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.

=head1 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.

=head2 Use callbacks only for public data

When you enable callbacks (JSONP) by setting C<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
C<allow_callback> is a static configuration of the View::JSON class.

See L<http://ajaxian.com/archives/gmail-csrf-security-flaw> for more.

=head2 Avoid valid cross-site JSON requests



( run in 1.903 second using v1.01-cache-2.11-cpan-39bf76dae61 )