I finally get PSGI and Plack!

Subject tags: 

For the past few months I’ve been meaning to get around to understanding PSGI and Plack; for various reasons, I guess. First, because it’s always good to keep abreast of what’s going on in the programming world; second, because they’re by Miyagawa, and really, anything by Miyagawa is worth looking into; third, because I’ve been writing a bunch of different web applications recently and wanted to know what the state of the art was.

As a bit of history, a few years back I wrote the Maypole web application framework, which spawned a wildly successful fork, Catalyst. (Incidentally, I’m always pleased when people do interesting and unexpected things with my software, and even more so when they’re successful.) The aims behind Maypole were to automate away a lot of the stuff you don’t need to care about when you’re writing a web application, such as dealing with the CGI or Apache environment, and to provide a easy way of getting you from data to action to template. But I started to feel that Maypole and similar frameworks were a bit heavy, so I played with a few other ideas: CGI::Application, and then HTTP::Engine. I liked HTTP::Engine. It’s very simple: it gives you a request object and you do what you need, write your own dispatch, and then hand it back a response object.

Here’s a very basic outline (note the lack of validation and error checking) of a Template Toolkit based web application with HTTP::Engine:

my $t = Template->new({ INCLUDE_PATH => "..." });

HTTP::Engine->new(
    interface => {
        module => "ServerSimple", request_handler => \&handle
    },
)->run;

sub handle {
    my $req = shift;
    my (undef, $action, @args) = split /\//, $req->path;
    my ($template, %vars) = SomeClass->$action(@args); # Do the work
    my $out;
    my $res = HTTP::Engine::Response->new;
    $t->process($template, \%vars, \$out)
      ? $res->body($out) : $res->body($t->error);
    return $res;
}

This is obviously very spiffy, but what has this got to do with PSGI and Plack? Well, HTTP::Engine does let you choose the backend - CGI, mod_perl, a standalone server as we’ve used in this example - which is great for us developers. We just care about getting the frontend code right, and the backend code is someone else’s problem. We can change environments very easily by changing the interface module in the code above.

In a sense, PSGI is very similar - it abstracts away the backend completely, so that now instead of writing for HTTP::Engine which implements the backend server for you as well, you’re writing for a specification, the PSGI specification, and the backend server is completely someone else’s problem. It’s like CGI ought to be - wrap up the environment of a request, then give back a response, and that’s your application, and forget the server.

Now of course that’s all very well, but you can’t just run code on “a specification”. You have to run it on something that implements the specification. There are a few things that implement the PSGI specification, and one of them is Plack. Plack actually contains a few PSGI servers, such as a CGI one, a mod_perl one, a standalone server… but hang on, isn’t that exactly what we had with HTTP::Engine?

Well, yes and no. For starters, by targeting PSGI, a specification, instead of an implementation, we’ve achieved separation of concerns between our application and our backend, which is cleaner. You don’t have to worry about supporting CGI (which was supposed to be the One True Interface between servers and web applications) or FastCGI or SpeedyCGI or mod_perl or whatever. You just code your application, and don’t worry about all that.

But that’s a bit of an airy-fairy reason for moving to a new technology.

The real reason you’re going to move to PSGI is holy shit it’s fast. There are some screamingly fast PSGI servers out there, and some which live directly inside emerging servers lika Perlbal and nginx.

OK, so how do we use this thing? If we’re starting from the HTTP::Engine based application above, we just change the initialization a bit:

 my $t = Template->new({ INCLUDE_PATH => "..." });

my $engine = HTTP::Engine->new(
    interface => {
        module => "PSGI", request_handler => \&handle
    },
);
sub { $engine->run(@_) };

Notice we changed the “run” to an anonymous sub. So when we run this code… it’s not going to do anything. But if we were to “do” or “eval” it, it will return a subroutine which forms the core of our application. And this is exactly what PSGI requires: your code provides a request-handling subroutine, which the PSGI server calls on each request. To “run” our code on a Plack server, we just say:

% plackup -a myapp.pl
Accepting connections at http://0:5000/

Or, if we like parallel requests,

 % plackup -a myapp.pl -s Standalone::Prefork
Accepting connections at http://0:5000/

Now, this all worked because we came via HTTP::Engine. Suppose we want to get rid of that and just do everything in “pure” PSGI. The documentation says:

If you’re writing a web application, not a framework, then you’re encouraged to use one of the web application frameworks that support PSGI, or use HTTP::Engine if you want to write a micro web server application.

But heck, that’s a bit boring. We are (sort of) writing a micro-framework in our example above - and it’s a good example for how to write other kinds of framework using the PSGI interface - so let’s rewrite it without HTTP::Engine. Instead, we’re going to use the Plack::Request module. Here’s how it looks:

use Template; use Plack::Request;
my $t = Template->new({ INCLUDE_PATH => "..." });
<b>sub {</b>
<b>    my $req = Plack::Request->new(shift);</b>
    my (undef, $action, @args) = split /\//, $req->path;
    my ($template, %vars) = SomeClass->$action(@args); # Do the work
    my $out;
<b>
    my $res = $req->new_response(200);
    $res->content_type('text/html');
</b>
    $t->process($template, \%vars, \$out)
      ? $res->body($out) : $res->body($t->error);
    return $res<b>->finalize</b>;
}

That’s all there is. That is a pico-framework that uses PSGI. The bits in bold are what we needed to change to migrate away from HTTP::Engine to using pure Plack::Request and Plack::Response classes. (Here’s another example of migrating to pure-PSGI, on a similar but rather more complete micro-framework I’ve whimsically called MicroMaypole; it’s the framework behind my Canary mail searching tool.)

And doesn’t it look nice and small now? That’s going to run quick, be easy to understand and easy to debug.

I \N{HEAVY BLACK HEART} PSGI.