How to use Dancer with Plack middlewares
This article is a repeat from last year's advent calendar due to time constraints - sorry! It's a valuable read for anyone who hasn't seen it before, though; the ability to use Plack middleware is one of the features that makes Plack so powerful.
Plack is an awesome addition to the Perl ecosystem. One of its key features is support for middlewares.
You can see a middleware as a Role: a reusable component shared between your applications. This component will act both as a client and as a server.
This article doesn't aim to present in details how a middleware works. If you're not yet familiar with Plack's middlewares, you can refer to these articles:
- http://search.cpan.org/~miyagawa/Plack-0.9951/lib/Plack/Middleware.pm
- http://advent.plackperl.org/2009/12/day-10-using-plack-middleware.html
Dancer and Plack
Let's start by creating a simple Dancer application:
$ dancer -a myapp + myapp + myapp/bin + myapp/bin/app.pl ...
Every Dancer application is a valid Plack application. When you're starting your project, you can choose between a standalone server, or using Plack:
$ ./bin/app.pl >> Dancer server 12481 listening on http://0.0.0.0:3000 == Entering the development dance floor ...
Doing this starts my application using Dancer's standalone server on port
3000 (by default; you can use the --port
command-line argument to change
this).
Now, let's use Plack to start this application:
$ plackup bin/app.pl HTTP::Server::PSGI: Accepting connections at http://0:5000/
This time, it's the PSGI's standalone server that serves our application, and
it is listening on port 5000 (this is the default chosen by Plackup; again,
you can use the --port
argument to change this).
Adding a first Middleware
For this example, we will add a basic middleware: Plack::Middleware::ETag. This one will append to all our responses a new header: ETag. The ETag is a mechanism to control cache validation. Most of the time, the value of the ETag is a checksum of the page content returned to the client. The client will then store this value, and next time it requests the same page, it will request the content only if the checksum has changed.
In your config.yml, add the following:
plack_middlewares: - - ETag
Now restart your application (with plackup), and let's do a request:
$ curl -D - http://localhost:5000 HTTP/1.0 200 OK Date: Tue, 09 Nov 2010 15:49:30 GMT Server: HTTP::Server::PSGI Content-Type: text/html; charset=UTF-8 X-Powered-By: Perl Dancer 1.1999_02 ETag: 5f6e450f378e384d4be6e0c081b9dd93026ff146 Content-Length: 5428
The ETag header has been added to your response. If you redo the request, you'll see that the ETag value is the same.
Let's add another middleware: Plack::Middleware::ConditionalGet. This middleware makes sure the application returns content to the client only if the content has been modified since the previous request:
plack_middlewares: - - ConditionalGET - - ETag
Note that the order is important.
$ curl -D - http://localhost:5000 \ -H "If-None-Match: 5f6e450f378e384d4be6e0c081b9dd93026ff146" HTTP/1.0 304 Not Modified Date: Tue, 09 Nov 2010 15:52:01 GMT Server: HTTP::Server::PSGI X-Powered-By: Perl Dancer 1.1999_02 ETag: 5f6e450f378e384d4be6e0c081b9dd93026ff146
This time there is no Content-Length header, because the value of the ETag header is the same, so we don't have any content returned for that request.
Content compression
Another common use case is the need to send content from the server to the client in a compressed format. For this, you can use Plack::Middleware::Deflater which will compress the content on-the-fly with gzip if the client supports this feature.
A simple:
plack_middlewares: - - Deflater
will do the trick.
Using the Debug panels
Some very useful middlewares to use while debugging your application are Plack::Middleware::Debug and Dancer::Debug.
Those middlewares will inject some HTML code in your page, providing lots of useful information about your application, the current request and the response returned. To activate their panels, add this to your configuration:
plack_middlewares: - - Debug - panels - - Parameters - Dancer::Version - Dancer::Settings - Memory
Next time you'll visit your application, you should see this panel on the right:
If you click on one of the element from the menu, the panel will open with something similar:
More complex
Some middlewares require a more complex configuration, and you won't use them as in our previous examples. For this example, we want to add a simple authentication system to access our application.
Edit your bin/app.pl
application, and replace the code with this one:
use Dancer; use myapp; use Plack::Builder; my $app = sub { my $env = shift; my $request = Dancer::Request->new($env); Dancer->dance($request); }; builder { enable "Auth::Basic", authenticator => sub { my ( $username, $password ) = @_; return $username eq 'admin' && $password eq 's3cr3t'; }; $app; };
First, we create a PSGI application (line 5). This application processes the request and returns a PSGI-compatible result. Next, we use the builder keyword, provided by Plack::Builder. Here we enable a middleware (Auth::Basic), and we create a code ref for the authentication method.
If you start your application with plackup, and load the page in your browser, you will be prompted for a username and a password to access the page.
Credits
A huge thanks to Marcel Grünauer and Tatsuhiko Miyagawa for the awesome Plack::Middleware::Debug.
Author
This article has been written by franck cuny <franck@lumberjaph.net>
for the Perl Dancer Advent Calendar 2010.
Copyright
Copyright (C) 2010 by franck cuny