Single Page Application with Perl Dancer
Article Index
Single Page Application with Perl Dancer
Verdict

Author: Gábor Szabó
Publisher: LeanPub
Pages: 133
Audience: New web developers
Rating: 3.5
Reviewer: Nikos Vaggalis

A book that gives people a reason to switch to Perl and the Dancer framework for developing for the Web

 

Of course Gabor needs no introduction, but it's worth mentioning that his is a later attempt of publishing a book on the Dancer framework in general. The first one, which I covered in Help Kickstart First Ever PerlDancer Book, was initiated by the Dancer's core devs themselves who unfortunately couldn't generate enough traction therefore the fund raising campaign failed. Fortunately this second campaign by Gabor proved successful to the point of exceeding its financial goals.

 

Banner

 

From the start you sense that it's going to be a very practical and hands-on tutorial as it doesn't waste any time and jumps straight to setting up the development environment using Vagrant and a Linux VM.Interesting choice considering that nowadays most use Docker, but probably done so because Docker is mainly directed to containerization of applications and not to that of full blown OSs.

So after setting up the environment we are next suggested two ways of installing Dancer.The first one is through the OS's package manager:

sudo apt-get install libdancer2-perl

which comes with the drawback that package managers are almost always out of sync with the latest software releases.Try for example to install Perl itself on a CentOS system;its main repository is still stagnating in version Perl 5.16, EOL since Oct 2016!Thus Gabor instead recommends using a CPAN client, and specifically cpanminus.

This is followed with the customary "Hello World" script:

#code/hello_world.psgi
use Dancer2;
get '/' => sub {
    return 'Hello World';
 };
__PACKAGE__->to_app;

 

This as well as being a Perl program also adheres to the PSGI standard and is run as: 

plackup hello_world.psgi

printing:

HTTP::Server::PSGI: Accepting connections at http://0:5000/
and waiting for incoming connections.

Plackup starts a HTTP::Server::PSGI (the default) server  instance on the foreground, which in turn launches our simple application.Thus visiting http://127.0.0.1:5000 from the browser is just going to print "Hello World" on the command line.Simple enough, but at this point I would expect a gentle introduction to Plack/PSGI in order to set the proper context;instead you are referred to the official documentation.

Before Gabor proceeds in writing more code, he pauses in order to bring the unit testing aspect into play, which he considers as important as writing the code itself, integrating it into the app's building life cycle from the very beginning.Thus in addition to the "Hello World" snippet we also get its unit testing equivalent:


#code/hello_world.t
use strict;
use warnings;
use 5.010;
use FindBin ();

use Test::More tests => 3;
use Plack::Test;
use HTTP::Request::Common qw(GET);

my $app = do "$FindBin::Bin/hello_world.psgi";
is( ref $app, 'CODE', 'Got app' );
my $test = Plack::Test->create($app);
my $res = $test->request( GET '/' );
ok( $res->is_success, '[GET /] successful' );
is( $res->content, 'Hello World', 'Content looks ok' );

 

That code is then broken down and analysed line by line and the chapter wraps up by encouraging the reader to go through a similar exercise by himself.

Of course a program should not be monolitihc in nature but instead be modularized, which is tackled next by breaking it down into "Multiple File Applications" where our "Hello World" script gets packaged in its own namespace.

Before we execute it again with plackup bin/app.psgi
we must tell plackup where to look for our new module or else encounter a rather cryptic error message:

Error while loading .../bin/app.psgi: Can't locate MySite.pm in @INC (you may need to install the MySite module)

No worries though, since the author does not just go through things when they work as planned, but also when they break down, taking care of potential gotchas like that:

This is a potentially very confusing error message because the reader will start to wonder how to “install the MySite module”. We don’t need to do that. We can change the list of directories where Perl will look for the MySite.pm file. We can do that in several way.

The one I used here was lib module to change @INC and using the $Bin variable of the FindBin to locate the path of the "lib" directory relative to the psgi file
use lib "$FindBin::Bin/../lib"; 

Pre-emptive tips like that can save an enormous amount of time and sanity.

perldancercover

click graphic for details on Leanpub

Routing

So far we've written a simple route handler as part of our "Hello World" script, which responds with returning that simple text to the browser when visiting the main entry point route '/' on port 5000 (http://127.0.0.1:5000) where our PSGI server instance listens, or when we run our test code with Plack::Test which imitates an ad-hoc web server instance:

get '/' => sub {
 return 'Hello World from module <a href="/other">Other page</a>';
};

 

At this point the notion of the Template is introduced, a mix of data  the server is about to return with HTML (and JQuery and CSS and so on) and Template Toolkit's Perl alike language.The template then generates the final document for the browser to render.

So given the route handler:

get '/other' => sub {
   return template 'other' => {
   title => 'Other World',
   name => 'Foo Bar',
  };
};

and the 'outer' template :

<html>
<head>
</head>
<body>
<h1>[% title %]</h1>
<a href="/other">Other page</a>
<div id="name">[% name %]</div>
</body>
</html>

'title' and 'name' end up replacing their corresponding [% %] placeholders.

But the browser is not necessarily the only client that can access our little website. It could also have been an Android application, in which case the website would probably respond with JSON rather than HTML. In fact as part of my Android Developer Nanodegree Capstone project, I did just that, amended the smadeseek.com website to cater for both clients and emit HTML when accessed through the browser and emit JSON when accessed through the Android application. The project required much more work than that, however, both Android-wise (Fragments, Loaders, AsyncTasks, Retrofit network calls, GSON parsing, Memory leaks, functional programming in Java) and server-side-wise (Dancer and Web based MVC, template rendering, Perl coding, connecting to Mysql, data modelling, etc). So if you are interested in finding out how I turned a HTML producing site to a JSON API endpoint, then you might want to take a look at Insider's Guide to Udacity Android Developer Nanodegree Part 7 - Full Stack Android.

The chapter then dives deeper into TT's constructs such as
[% FOREACH %]
and
[% IF condition %]

presenting more elaborate code based on them.The TT code you can end up with can be quite complex since you are free to use Perl's data structures such as hashes and arrays, just like I did when needing to implement a humble HTML drop down menu:

<span style="display:block"> CPU Brands/Models </span>
<select name="CPU" id="PerformanceCpuBrandChild" 
                                class="childs" >
   <optgroup label=""  class="optgroup">
      <option value="-1">All</option>
   </optgroup>
   [% FOREACH cpukey IN cpuhash.keys.sort %] 
   <optgroup label="[% cpukey %]"  class="optgroup">
      <option selected="selected" value="0">
            All [% cpukey %] models</option>
      [% FOREACH cpuinnerhash IN cpuhash.$cpukey %]
      <option value="[% cpuinnerhash.item('CPUId') %]"> 
          Model: [% cpuinnerhash.item('CPUType') %]
         [% cpuinnerhash.item('CPUModel') %] </option>
      [% END %]
   </optgroup>
   [% END %]  
</select>

Next are Layouts which are used to group templates together, as well as templates for e-mails and templates that include static content such as CSS and Images.



Last Updated ( Saturday, 19 May 2018 )