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:

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