4

I have a problem working with the built in Perl Dancer serializer for JSON and JSON arrays.

I activated the serializer in the app.pl file:

#!/usr/bin/env perl
use Dancer;
use main;

set serializer => 'JSON';

dance;

In the module itself I tested the JSON parsing like this:

post '/test/' => sub {
    my $params = request->params;

    debug('Test: ', $params);
};

Now I wanted to make sure the JSON gets parsed as expected, so I tried using cURL to understand the way the serializer works:

curl -H "Content-Type: application/json" -X POST http://localhost:3000/test/ -d '{ "Name" : "foo", "email" : "bar" }'

The result was as expected:

Test: {'Name' => 'foo','email' => 'bar'}

But trying to send an array:

curl -H "Content-Type: application/json" -X POST http://localhost:3000/test/ -d '[{ "Name" : "foo", "email" : "bar" }]'

Resulted in:

Test: {}

I expected the serializer to return an array reference, but it seems like it returns an empty hash. I tried using the serializer the other way around, but encoding JSONs seems to work as expected. What have I done wrong?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
meltdown90
  • 251
  • 1
  • 11
  • What does this do? `curl -H "Content-Type: application/json" -X POST http://localhost:3000/test/ -d '{ "Name" : "foo", "email" : "bar" },{ "Name" : "baz", "email" : "baz@baz.newt" }'` – user3183018 Aug 07 '14 at 11:44
  • Sorry, was going off the [Dancer doc on params](http://search.cpan.org/dist/Dancer/lib/Dancer.pm#params) which says it deals with hash in scalar context. Thought might be able to force it to hash. – user3183018 Aug 07 '14 at 12:00
  • Thank you anyways - it is very much possible that I use the wrong method to access the JSON I send. I tried to create a similar JSON: `curl -H "Content-Type: application/json" -X POST http://localhost:300/test/ -d '{ "testA" : { "Name" : "foo", "email" : "bar" }, "testB" : { "Name" : "baz", "email" : "baz@baz.newt" }}'` this return the expected: `Test: {'testA' => {'Name' => 'foo','email' => 'bar'},'testB' => {'Name' => 'baz','email' => 'baz@baz.newt'}}` But putting it in an array `[ { "Name" : "foo", "email" : "bar" }, { "Name" : "baz", "email" : "baz@baz.newt" }]` still returns `Test: {}` – meltdown90 Aug 07 '14 at 12:06

2 Answers2

4

Thought I had code that did this but, was mistaken.

I couldn't get params to parse anything with any depth. Maybe that's by design but, not really clear to me from the documentation.

Using the from_json function directly you can parse request->body which contains the POST'd JSON string:

Note: I use'd Data::Dumper to print variable contents to try to make it a little clearer.

post '/test/' => sub {
 #my @params =   params  ;
 #my @params =   request->body;
 my $body = request->body;

 my $j_O = from_json( $body );

 #deubg( 'Test1: ' . Dumper( request->body ) );
 #debug( 'Test2: ' . Dumper( request->params ) );
 #debug( 'Test3: ' . Dumper( { params }  ) );
 debug( 'Test4: ' . Dumper( $body ) );
 debug( 'Test5: ' . Dumper( $j_O ) );


};

OUTPUT:

[27993] debug @0.001528> [hit #2]Test4: $VAR1 = '[ { "Name" : "foo", "email" : "bar" }, { "Name" : "bar"} ]'; in /media/truecrypt1/Projects/Perl5+/Dancer/Test/lib/Test.pm l. 23
[27993] debug @0.001772> [hit #2]Test5: $VAR1 = [
          {
            'email' => 'bar',
            'Name' => 'foo'
          },
          {
            'Name' => 'bar'
          }
        ];
user3183018
  • 354
  • 1
  • 9
  • Thank you for your answer. I tried it with `[ { "Name" : "foo", "email" : "bar" }, { "Name" : "baz", "email" : "baz@baz.newt" }]` which returns nothing. For this hash `{ "Name" : "foo", "email" : "bar" }` I get 4 debug messages: `Test: email; Test: bar; Test: Name; Test: foo` I'd be glad if you could update your answer after you had a look at your code! – meltdown90 Aug 07 '14 at 12:45
  • Hopefully you will get a better more complete answer before I can get to my code. :) – user3183018 Aug 07 '14 at 13:33
  • Thank you very much - this works now! Seems like the JSON serializer wasn't my problem after all. – meltdown90 Aug 08 '14 at 13:44
  • Thank you!! I can now get the JSON Data passed from $http.post() from my Angular app in my Dancer2 backend. – Milean Feb 12 '16 at 18:16
1

I have come across this same problem. The Dancer serializer framework cannot de-serialize anything other than HASH data types. I suspect this is because internally in Dancer you can do things such as params->{'foo'} to get elements. This code in Dancer::Serializer (~line 110) is the reason for this.

if (!ref $new_params or ref $new_params ne 'HASH') {
    return $request;
}

For me, there are some methods where I need to pass in an array to the request. This was causing me not to be able to use the standard serializer framework, but I wanted to keep the same options in my config.yml.

Here is my solution:

  my $json_object = from_json(request->body, config->{'engines'}->{'JSON'});

This will return a JSON object (Array or HashRef) using the configuration option you have specified in your config.yml for the JSON engine. You may or may not want to wrap this in an eval.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jr.
  • 4,503
  • 7
  • 44
  • 62