PSGI and Plack

The future of Perl web programming

Author:Baldur Kristinsson <bk@mbl.is>
Location:Nordic Perl Workshop, Reykjavík
Date:2010-11-14

Overview

Testimonials (1)

"Wow, this is nothing short of awesome. A big ++ to the entire PSGI/Plack team!"

—Stevan Little

"I love this... I think it's exactly the right answer to what I was looking for"

—Benjamin Trott

Testimonials (2)

"This is something we've needed for a long time: a clean and simple way to respond to HTTP requests without the cruft of CGI"

—Yuval Kogman

"miyagawa++ # fucking awesome"

—Matt S. Trout

What are PSGI and Plack?

PSGI (1) -- Antecedents

PSGI (2) -- Purpose

The simplicity of PSGI

my $app = sub {
    my $env = shift;
    return [
        200,
        [ 'Content-Type' => 'text/plain' ],
        [ 'Hello, ', $env->{REMOTE_ADDR} ]
    ];
};

(You don't actually need to worry about this unless you're a framework or middleware developer)

The PSGI $env

Plack - The PSGI Toolkit

Plack Components (1)

Plack Components (2)

Plack Components (3)

Plack Components (4)

Plack Components (5)

Some Other Modules

Deployment

Two aspects of deployment in this context:

Plack Web Servers (1)

Plack Web Servers (2)

Plack Web Servers (3)

Framework Support (1)

Framework support (2)

Middleware Example (1)

Middleware Example (2)

package Plack::Middleware::ESI;
use strict;
use warnings;
use parent qw(Plack::Middleware);
use Plack::Util;
use LWP::UserAgent;
our $VERSION = 0.01;

Middleware Example (3)

sub call {
    my $self = shift;
    my $res = $self->app->(@_);
    $self->response_cb($res, sub {
        my $res = shift;
        if ($self->_ct_is_text($res)) {
            return sub {
                my $chunk = shift;
                return $self->_esi($chunk)
            };
        }
    });
}

Middleware Example (4)

sub _esi {
    my ($self, $chunk) = @_;
    return unless defined $chunk;
    my $rx = qr{(<esi:include src="([^"]+)"[^>]*/>)};
    while ($chunk =~ $rx) {
        my ($tag, $url) = ($1, $2);
        my $txt = $self->_ua->get($url)->content;
        $chunk =~ s/\Q$tag\E/$txt/g;
    }
    return $chunk;
}

Middleware Example (5)

sub _ct_is_text {
    my ($self, $res) = @_;
    my $h = Plack::Util::headers($res->[1]);
    my $ct = $h->get('Content-Type');
    return $ct =~ /^text/ ? 1 : undef;
}
sub _ua {
    my $self = shift;
    my $ua = new LWP::UserAgent;
    $ua->timeout(5);
    return $ua;
}

Using Our New Middleware

use Plack::Builder;
my $app = sub {
    return [ 200,
      ['Content-Type' => 'text/plain'],
      ['<esi:include src="http://google.com/" />']
    ];
};
builder {
    enable "ESI";
    $app;
};

Conclusion

Questions?

Thanks!