Using Perl as a framework for your web site
Summary:
Use Perl as a simple and powerful framework for your web site; this article will demonstrate how easy it is to get going and then customise a Plack application for your own needs.
Perl has been through a revolution over the last few years - 'Modern Perl', based on experienced and effective Perl 5 programmers knowledge, is about using the languages idioms and taking advantage of the best of CPAN.
We will be demonstrating how to create a web site using Plack, a 'Moden Perl' tool. Most Perl frameworks work with (or are migrating to) Plack, therefor it will be easy to integrate one of those later should you want to.
Plack is Perl superglue for web frameworks and web servers. Plack sits between your code (whether you use a web framework or not) and the web server (Apache, Starman, etc). This means that you (and your framework) do not need to worry about specifics of a web server, and vice-versa.
Let's get you setup... we are going to use cpanm (from App::cpanminus) to download and install modules into your local::lib (so you do not need root access)
Initial setup:
# archive of any existing cpan configuration mv ~/.cpan ~/.cpan_original # Then one of the following: # if you can run wget wget -O - http://cpanmin.us/ | perl - local::lib App::cpanminus && echo 'eval $(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)' >> ~/.bashrc && . ~/.bashrc # OR if you can run curl curl -L http://cpanmin.us/ | perl - local::lib App::cpanminus && echo 'eval $(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)' >> ~/.bashrc && . ~/.bashrc # otherwise, download the contents of http://cpanmin.us to a file called cpanmin.us, make it executable and then run: ./cpanmin.us local::lib App::cpanminus && echo 'eval $(perl -I$HOME/perl5/lib/perl5 -Mlocal::lib)' >> ~/.bashrc && . ~/.bashrc
Setting up Plack
cpanm Plack
# Please also run this as we will us it in the demonstration later
cpanm Plack::Middleware::TemplateToolkit
The perl5 folder in your home directory will now have all the modules you need.
The next step is to create a .psgi configuration file which will allow us to return a
web page.
# Tell Perl where our lib is (ALWAYS use this)
use lib "$ENV{HOME}/perl5/lib/perl5";
# ensure we declare everything correctly (ALWAYS use this)
use strict;
# Give us diagnostic warnings where possible (ALWAYS use this)
use warnings;
# Allow us to build our application
use Plack::Builder;
# A basic app
my $default_app = sub {
my $env = shift;
return [
200, # HTTP Status code
[ 'Content-Type' => 'text/html' ], # HTTP Headers,
["All is good"] # Content
];
};
# Return the builder
return builder {
$default_app;
}
Save this to a file, called 1.psgi, then use the plackup command to start your web server from the command line as follows:
plackup 1.psgi
You will see:
HTTP::Server::PSGI: Accepting connections at http://SERVER_IP:5000/
Using your web browser, go to http://SERVER_IP:5000/, if you are developing on your desktop computer then http://localhost:5000/ will work. You should now see a page with 'All is good'. In fact if you go to any page this is what you will see, e.g. http://localhost:5000/any_page.html because we are always returning this, irrespective of the request.
You will notice that on the command line you can see the access logs for the web server, this is because Plack defaults to development mode and turns on a few extra middleware layers for you, specifically AccessLog, StackTrace and Lint.
To see StackTrace in operation comment out line 27 of 1.psgi by adding a hash (#) in front of it:
# ["All is good"] # Content
Restart your plackup command (type Ctrl+C to stop the process, then run plackup 1.psgi to start it).
Now in your web browser go to http://localhost:5000/ again and you will see
a StackTrace of the error. Note the main error message at the top of the page "response needs to be 3 element array, or 2 element in streaming". You can then follow each step of the trace, click on the 'Show function arguments' and 'Show lexical variables' links under any section of the trace to help debug the issue.
Remove the # and restart, so we have a working .psgi file again.
Development
There are several command line arguments to the plackup command, running perldoc plackup command will
show you the documentation. The most used is '-r' or '--reload' this tells plackup to monitor you .psgi file
(if you have a 'lib' directory along side your .psgi file it will also be monitored).
plackup -r 1.psgi
Extending your application
Plack already has many useful applications which you may want to integrate with your web portal, here for example we are using Plack::App::Directory to get a directory listing and to serve it's content as static files. We will use Plack::App::URLMap to choose which URL we want to 'mount' this application on.
use lib "$ENV{HOME}/perl5/lib/perl5";
use strict;
use warnings;
use Plack::Builder;
# 'mount' applications on specific URLs
use Plack::App::URLMap;
# Get directory listings and serve files
use Plack::App::Directory;
my $default_app = sub {
my $env = shift;
return [ 200, [ 'Content-Type' => 'text/html' ], ["All is good"] ];
};
# Get the Directory app, configured with a root directory
my $dir_app = Plack::App::Directory->new( { root => "/tmp/" } )->to_app;
# Create a mapper object
my $mapper = Plack::App::URLMap->new();
# mount our apps on urls
$mapper->mount('/' => $default_app);
$mapper->mount('/tmp' => $dir_app);
# extract the new overall app from the mapper
my $app = $mapper->to_app();
# Return the builder
return builder {
$app;
}
If you visit http://localhost/tmp/ in your browser you will now see a directory listing of '/tmp/' - also not http://localhost/anything_else.html still hits the default_app which we built.
More Middleware and Apps
There are many Plack::Apps and Plack::Middleware modules available to help with common tasks. We are going to look at Plack::Middleware::TemplateToolkit, which parses files through the templating engine Template-Toolkit (TT). Images and other static content should not go through TT, so we are going to configure Plack::Middleware::Static to directly serve files with specific extensions. On top of this we want to have a nice looking page when there is a 404 (file not found), for this we will use Plack::Middleware::ErrorDocument. All the code we need to add is as follows:
# A link to your htdocs root folder
my $root = '/path/to/htdocs/';
# Create a new template toolkit application (which we will default to)
my $default_app = Plack::Middleware::TemplateToolkit->new(
INCLUDE_PATH => $root, # Required
)->to_app();
return builder {
# Page to show when requested file is missing
# this will not be processes with TT
enable "Plack::Middleware::ErrorDocument",
404 => "$root/page_not_found.html";
# These files can be served directly
enable "Plack::Middleware::Static",
path => qr{[gif|png|jpg|swf|ico|mov|mp3|pdf|js|css]$},
root => $root;
# Our application
$default_app;
}
At this stage it is probably worth investigating one of the many web frameworks which offer PSGI support, so can be run with Plack. These frameworks offer far structure and support for doing more complex tasks. Have a look at Catalyst, Mojolicious or Dancer. The Perl.org web frameworks white paper discusses just a few of the advantages of using a framework.
Further resources
Perl has a vast number of modules available for use on CPAN. The only real problem being to work out which are best to use. A good place to start is Task::Kensho which recommends current best practices.