Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl Catalyst - Obtaining JSON data from AJAX POST request

I am trying to obtain the JSON data that is sent to the server via an AJAX POST when a button is clicked on my homescreen page on my Catalyst application:

The AJAX POST that sends the JSON data to the server:

$("#saveCanvasStates").click(function () {
// button to save canvas states to a database

// Serialize the states array
var JsonStringForTransport = JSON.stringify({stateForUserNumber7: states});

// POST the JSON to the server
var thePost = $.ajax({
    url: 'homescreen',
    type: 'POST',
    dataType: 'json',
    data: JsonStringForTransport,
    contentType: 'application/json; charset=utf-8'
});

I also have the following Catalyst Controller for the homescreen page which the button that sends the AJAX POST is located on:

Catalyst Controller:

package MyProject::Controller::Homescreen;

use strict;
use warnings;
use parent 'Catalyst::Controller';
use Data::Dumper;

__PACKAGE__->config->{namespace} = '';

sub homescreen :Path('/homescreen') :Args(0)  {

        my ( $self, $c ) = @_;

        $c->stash({title => 'Home Screen',
                   pagetype => 'html',
                   template => 'homescreen.html'
                 });


#here is where I think I need to obtain the JSON data from the AJAX POST request 
#and save it to my database

}

1;

Once I have this JSON data in a form I can work with I will then be saving it to a Postgres database.

From looking at the CPAN docs for Catalyst::Request, as it's my understanding this is what to refer to when dealing with request stuff, it's possible to use the following to do stuff with AJAX POST data?:

  • $c->$req->body_data
  • $c->$req->body_parameters
  • $c->$req->body_params

But I am unsure about the best way to get the data into a form I can then insert into my database and which one of the methods should be used in preference?

I can find very little documentation that has helped me.

Update (relating to RET's answer)

I definitely have body_data to display because when I do:

print Dumper($c->req->body_data);

I get the following printed in my development server log:

$VAR1 = {
          'stateForUserNumber7' => [
                                     {
                                       'width' => 102,
                                       'offsetY' => 56,
                                       'x' => 11,
                                       'height' => 102,
                                       'image' => {},
                                       'y' => 14,
                                       'contextIndex' => 2,
                                       'dragging' => bless( do{\(my $o = 0)}, 'Cpanel::JSON::XS::Boolean' ),
                                       'offsetX' => 73
                                     },
                                     {
                                       'width' => 102,
                                       'offsetY' => 34,
                                       'x' => 103,
                                       'height' => 102,
                                       'image' => {},
                                       'y' => 17,
                                       'contextIndex' => 3,
                                       'dragging' => $VAR1->{'stateForUserNumber7'}[0]{'dragging'},
                                       'offsetX' => 46
                                     }
                                   ]
        };
[info] *** Request 15 (1.250/s) [17427] [Fri Dec  6 00:02:22 2013] ***
[debug] Path is "homescreen"
[debug] "POST" request for "homescreen" from "192.168.1.100"
[debug] Rendering template "homescreen.html"
[debug] Response Code: 200; Content-Type: text/html; charset=utf-8; Content-Length: 7010
[info] Request took 0.025343s (39.459/s)
.------------------------------------------------------------+-----------.
| Action                                                     | Time      |
+------------------------------------------------------------+-----------+
| /homescreen                                                | 0.014044s |
| /end                                                       | 0.001992s |
|  -> Organiser::View::TT->process                           | 0.001058s |
'------------------------------------------------------------+-----------'

Further update

This is the error it gives in the development server output when using -d:

Caught exception in Organiser::Controller::Homescreen->homescreen "Can't use an undefined value as a HASH reference at /home/fred/Organiser/script/../lib/Organiser/Controller/Homescreen.pm line 21."

This is the error I get from Stack Trace when running the development server:

Stack Trace
Package                             Line    File
Organiser::Controller::Homescreen   21    /home/fred/Organiser/lib/Organiser/Controller/Homescreen.pm

18: 
19: print STDERR Dumper $c->req->body_data; 
20: 
21: foreach my $data (@{$c->req->body_data->{stateForUserNumber7}}) {     <-- it highlights in bold this line
22:      print "DOLLAR DATA $data\n"; 
23: } 
24:

Organiser::Controller::Root     17  /home/fred/Organiser/lib/Organiser/Controller/Root.pm

14: sub index :Path :Args(0) { 
15: my ( $self, $c ) = @_; 
16: 
17: $c->forward('homescreen');       <-- it highlights in bold this line
18: 
19: } 
20: 

Using Firebug this is the POST request that is occurring (after I comment out the foreach that is making it error)

Source
{"stateForUserNumber7":[{"dragging":false,"contextIndex":4,"image":{},"x":108,"y":4,"width":102,"height":102,"offsetX":45,"offsetY":65}]}

It is always stateForUserNumber7 (I should have named it master_user or something really)

like image 210
yonetpkbji Avatar asked Dec 03 '13 22:12

yonetpkbji


2 Answers

Although the built in logging stuff is great when you are making logs to persist and to do analysts on, I find it not terribly using for basic debugging. I've lately been using Devel::Dwarn which is an easy install. This is like a warn dumper + rolled up very neatly.

If you start your app like so

perl -MDevel::Dwarn ...

You can stick Dwarn $ref and get a nice stderr output:

Dwarn $c->req->body_data

Should give you a neat review. Plus if you drop the -MDevel::Dwarn you'll get errors in all the places you accidentally left Dwarn out (something I should have done with the borked release of Runner 002 last month).

If that is confusing to you just try:

(after cpanm Devel::Dwarn)

use Devel::Dwarn;
Dwarn $c->req->body_data

You should get a deep structure output to your console. Best of luck!

like image 164
John Napiorkowski Avatar answered Sep 20 '22 20:09

John Napiorkowski


My other answer is (hopefully) useful information for anyone debugging Catalyst/JSON issues. But subsequent updates to the question have shown the problem here is actually something entirely different.

There are not enough actions to support the required functionality here. If the index action forwards to the homescreen action which renders the homescreen.html template, then the $.json() call has to be to some other action which is responsible for handling the data save request and nothing else.

package MyProject::Controller::Homescreen;

use strict;
use warnings;
use parent 'Catalyst::Controller';
use JSON;

sub homescreen :Path('/homescreen') :Args(0)  {

    my ( $self, $c ) = @_;
    $c->stash({title => 'Home Screen',
               pagetype => 'html',
               template => 'homescreen.html'
    });
}

sub savecanvasstates :Local {
    my ($self, $c, @args) = @_;
    my $p = $c->req->param->{stateForUserNumber7} || die "wrong parameters!";
    my $result = {};
    foreach my $r (@{$p}) {
        # ... do something with $r->{x} etc
        $result->{output} = # construct whatever object the ajax caller expects
    }
    $c->res->body(to_json($result))
}

1;

And in some nearby JavaScript:

$("#saveCanvasStates").click(function () {
    // button to save canvas states to a database

    // Serialize the states array
    var JsonStringForTransport = JSON.stringify({stateForUserNumber7: states});

    // POST the JSON to the server
    var thePost = $.ajax({
        url: 'savecanvasstates',
        type: 'POST',
        dataType: 'json',
        data: JsonStringForTransport,
        contentType: 'application/json; charset=utf-8',
        success: function(data, textStatus){ ... }
        error: function(XMLHttpRequest, textStatus, errorThrown){ ... }
    });
});

I hope all that makes what you have to do clearer.

like image 37
RET Avatar answered Sep 16 '22 20:09

RET