Discipulus has asked for the wisdom of the Perl Monks concerning the following question:

Hello monks,

I'm finally trying to take out some rusty from my web-fu and, after a 12+ years hyatus, i take Dancer2 and I'm experimenting with it with the precious support of 1nickt, but, in my wide ignorance, I found that Dancer2 manuals and tutorials give many things as already known and understood, which is not my case.

Question

My main problem at the moment is to understand the differences and the usage of param params route_parameters query_parameters and body_parameters

I have a template form.tt and I pass to it <% form_url %> to be used as action of the submitted form: <form action="<% form_url %>" method=post>

Then in my application module I have the folowing route:

any ['get', 'post'] => '/form' => sub { #var form_url => uri_for('/form'); # template 'form' => { 'title' => 'form', # 'form_url' => 'http://127.0.0.1:5000/form'# uri_for('/form') # }; # POST request if ( request->method() eq "POST" ) { debug "post method"; # when this is printed out +??? # process form input if ( query_parameters 'search_for') { # nor query_parameter +s->get('search_for') # debug "param defined"; this doe +s not work, why? "defined ".(query_parameters 'search_for'); # this even do +es not show up } # this works unless a template is called # "searching for ==>".(param 'search_for')."<==" ; template 'form' => { 'title' => 'formtest POST', 'search_for' => param 'search_for'}; } # GET request else { template 'form' => { 'title' => 'formtest GET', 'form_url' => uri_for('/form') }; } };

I just can make the above working using param that by docs seems to be discouraged. it is not just the case where query_parameters is appropriate? How make it to work?

Further informations

I never found in Dancer2 docs things about parameters explained for dummies, as me. I'm trying to collect every possible combination of param usage and relative working URL examples to propose, maybe in near future, some addendum to official docs.

What I have already done (again only because of the help 1nickt gave to me) is on github where you can find the above route and a working simple AJAX implentation. If i reach some good degree i'l change this repository into something like step by step tutorial on parameters and AJAX.

Thanks for the attention

L*

PS any ideas about a better way to program with Dancer2 is welcome as welcome will be eventual fork/pr for the above github repository

There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

Replies are listed 'Best First'.
Re: Dancer2 parameters understanding and usage
by 1nickt (Canon) on Nov 29, 2017 at 13:05 UTC

    Hi Discipulus,

    The main problem you have with the posted code is that you are trying to retrieve the value of your body parameters with the method for retrieving query parameters.

    When you get data POSTed from a form, it's transported in the body of the HTTP request (in general, not specific to Dancer). Query parameters are those passed as the query string, e.g. /form?search_for=truth.

    Dancer2 provides various ways to access your parameters.

    • my $href_of_all_params = params;
    • my $single_val = param 'search_for';
    • my $single_val = body_parameters->get('search_for');

    The three methods for retrieving a certain class of params, body_parameters(), query_parameters(), route_parameters() all return a Hash::MultiValue object, so it is necessary to call a method to get values.

    The reason for using Hash::MultiValue, and the reason these methods are recommended in the Dancer2 doc, is so you can, well, have multiple values. This is most commonly seen in query params, e.g.:

    /form?multival=bar&multival=baz
    To get all the values for multival you would use:
    my @values = query_parameters->get_all('multival');
    (see Hash::MultiValue).

    The documentation for Dancer2 is, like most of the large frameworks, extensive and somewhat tricky to navigate. But it's all there in the manual:

    Also:

    • You don't see any log output until you configure a logger in your config.yml. E.g.:
      logger: Console engines: logger: Console: log_level: debug log_format: '[%f l.%l] %m'
      (Shameless plug: I recommend Dancer2::Logger::LogAny.)
    • You don't really need to provide the full URL for the form action, a relative path will normally suffice.
    • The title value that gets passed to the template engine is consumed by the tag in views/layouts/main.tt for the HTML title of the page. I usually use a different term, "headline" for the title of the content of the page, for clarity.

    I made a new pull request to your Github repo incorporating all the above suggestions into your app. The relevant route handler code is shown below.

    Hope this helps!

    any ['get', 'post'] => '/form' => sub { # POST request if ( request->method() eq "POST" ) { debug "method: POST"; debug 'All params: ' . Dumper { params }; debug 'One param from href: ' . params->{'search_for'}; debug 'Form params: ' . Dumper body_parameters->mixed; + # see Hash::MultiValue debug 'Param "search_for": ' . body_parameters->get('search_f +or'); debug 'Another way: ' . param 'search_for'; template 'form' => { title => 'Form Test', headline => 'form test POST', form_url => '/form', search_for => param 'search_for', # least typing ;-) }; } # GET request else { template 'form' => { title => 'Form Test', headline => 'formtest GET', form_url => '/form', }; } };


    The way forward always starts with a minimal test.
      Hello 1nickt++ and ++1nickt (even if we know this leads to an undefined behaviour..)

      > The main problem you have with the posted code is that you are trying to retrieve the value of your body parameters with the method for retrieving query parameters.

      > When you get data POSTed from a form, it's transported in the body of the HTTP request (in general, not specific to Dancer). Query parameters are those passed as the query string, e.g. /form?search_for=truth.

      OMG i completely misunderstood the terminology and I repeat, docs have not helped me a lot. I was sure (nothing worst to be convinced of something wrong) that query parameters were these passed via POST and body ones were something defined in the body of the routes, like private variables..

      My approsimative understanding of the web mechanism (i'd say underlying form) does not revealed immediatly to me that query parameters was for things passed via query in the URL like /form?search_for=truth and that body ones were reffered to the body of the incoming POSTed request.

      I also misunderstood route parameters at first glance: i've tested them many times with URLS like /form?search_for=truth before understending that the correct way is:

      get '/routeparam/:name?' => sub { # ok http://127.0.0.1:5000/routeparam/here_my_name "Hey " . route_parameters->get('name') . ", welcome here!"; };

      All your others suggestions and contributions are precious for me.

      I have already read all the docs you linked above but i'm even more convinced now that basic docs need some integrations for not already web developpers. As soon as I have got all these basic dance moves I'll make a pr for the doc part of Dancer2 probably for the main manual.

      L*

      There are no rules, there are no thumbs..
      Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

        Just to be clear about route parameters. You can define any part of a URL path as a parameter. You don't need a 'static' part to prefix a param, although a lot of apps, particularly REST APIs, do that. You can also use route and query (and even body) params together. For example:

        get '/foo/:name/bar/:age/:occupation' => sub { return '<pre>'.Dumper({ params }).'</pre>'; };
        If the user requests the following URL:
        http://localhost:5000/foo/Discipulus/bar/42/student?country=Eataly&cit +y=Roma
        The app displays in the browser:
        <pre>$VAR1 = { 'name' => 'Discipulus', 'age' => '42', 'city' => 'Roma', 'occupation' => 'student', 'country' => 'Eataly' }; </pre>

        Also see: Dancer2 Advent Calendar: New Parameters Keywords. (The Dancer2 Advent Calendar is a great source of documentation and examples.)


        The way forward always starts with a minimal test.