Add a json_options key to the REST controller
Tomas Doran [Wed, 1 Sep 2010 22:03:45 +0000 (23:03 +0100)]
Changes
lib/Catalyst/Action/Deserialize/JSON.pm
lib/Catalyst/Controller/REST.pm
t/json.t
t/lib/Test/Serialize/Controller/JSON.pm [new file with mode: 0644]

diff --git a/Changes b/Changes
index fab2f3f..51079dc 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,3 +1,5 @@
+  Add rest_serializer_json_options config key useable to set options
+  like relaxed => 1 to be passed to the JSON serializer (Ton Voon)
 
   Make Data::Dumper unserializer safer by using a Safe compartment (Ton Voon)
 
index b9a40df..215f959 100644 (file)
@@ -4,7 +4,7 @@ use Moose;
 use namespace::autoclean;
 
 extends 'Catalyst::Action';
-use JSON qw( decode_json );
+use JSON;
 
 our $VERSION = '0.85';
 $VERSION = eval $VERSION;
@@ -23,7 +23,13 @@ sub execute {
     }
 
     if ( $rbody ) {
-        my $rdata = eval { decode_json( $rbody ) };
+        my $json = JSON->new->utf8;
+        if (my $options = $controller->{json_options}) {
+            foreach my $opt (keys %$options) {
+                $json->$opt( $options->{$opt} );
+            }
+        }
+        my $rdata = eval { $json->decode( $rbody ) };
         if ($@) {
             return $@;
         }
index 4c017d8..2c0cb17 100644 (file)
@@ -146,6 +146,12 @@ Uses L<JSON> to generate JSON output.  It is strongly advised to also have
 L<JSON::XS> installed.  The C<text/x-json> content type is supported but is
 deprecated and you will receive warnings in your log.
 
+You can also add a hash in your controller config to pass options to the json object.
+For instance, to relax permissions when deserializing input, add:
+  __PACKAGE__->config(
+    json_options => { relaxed => 1 }
+  )
+
 =item * C<text/javascript> => C<JSONP>
 
 If a callback=? parameter is passed, this returns javascript in the form of: $callback($serializedJSON);
index 673c0a9..35d6059 100644 (file)
--- a/t/json.t
+++ b/t/json.t
@@ -10,7 +10,7 @@ use utf8;
 eval 'use JSON 2.12';
 plan skip_all => 'Install JSON 2.12 or later to run this test' if ($@);
 
-plan tests => 9;
+plan tests => 11;
 
 use_ok 'Catalyst::Test', 'Test::Serialize';
 
@@ -36,4 +36,14 @@ for ('text/x-json', 'application/json') {
     is_deeply($mres_post->content, $exp, "POST data matches");
 }
 
+{
+    my $t = Test::Rest->new('content_type' => 'application/json');
+    my $json_data = '{ "sushi":"is good for monkey", }';
+    my $mres_post = request($t->post(url => '/monkey_put', data => $json_data));
+    ok( ! $mres_post->is_success, "Got expected failed status due to invalid JSON" );
+
+    my $relaxed_post = request( $t->post(url => "/monkey_json_put", data => $json_data));
+    ok( $relaxed_post->is_success, "Got success due to setting relaxed JSON input" );
+}
+
 1;
diff --git a/t/lib/Test/Serialize/Controller/JSON.pm b/t/lib/Test/Serialize/Controller/JSON.pm
new file mode 100644 (file)
index 0000000..fcc07a3
--- /dev/null
@@ -0,0 +1,29 @@
+package Test::Serialize::Controller::JSON;
+
+use namespace::autoclean;
+use Moose;
+
+BEGIN { extends qw/Catalyst::Controller::REST/ };
+
+__PACKAGE__->config(
+    'stash_key' => 'rest',
+    'json_options' => {
+        relaxed => 1,
+    },
+    'map'       => {
+        'text/x-json'        => 'JSON',
+    },
+);
+
+sub monkey_json_put : Path("/monkey_json_put") : ActionClass('Deserialize') {
+    my ( $self, $c ) = @_;
+    if ( ref($c->req->data) eq "HASH" ) {
+        my $out = ($c->req->data->{'sushi'}||'') . ($c->req->data->{'chicken'}||'');
+        utf8::encode($out);
+        $c->res->output( $out );
+    } else {
+        $c->res->output(1);
+    }
+}
+
+1;