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
- What are PSGI and Plack?
- Benefits of PSGI
- Cool things you can do with Plack
- Server and framework support
- The future
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 is an interface specification
- Plack is a reference PSGI implementation
- Plack is also a set of tools and middleware
- Main author: Tatsuhiko Miyagawa
PSGI (1) -- Antecedents
- Inspired by WSGI from the Python world
- WSGI is a simple and universal interface between a web server
and a Python web application or framework
- PSGI is a simple and universal interface between a web server
and a Perl web application or framework
- WSGI is old, problematic for e.g. Comet-style apps - PSGI
improves on WSGI in this area
- Plack has also borrowed ideas from Rack, the Ruby counterpart
of WSGI
PSGI (2) -- Purpose
- Prevent duplication of effort by app/framework authors
- Overcome deployment restrictions
- Bring WSGI-style Middleware into the Perl world
- Facilitate writing long-polling, Comet-style apps in Perl
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
- CGI-like headers: REQUEST_METHOD, SCRIPT_NAME, PATH_INFO,
REQUEST_URI, QUERY_STRING, HTTP_*, etc.
- PSGI server info: psgi.version, psgi.url_scheme,
psgi.multithread, psgi.multiprocess, psgi.run_once,
psgi.nonblocking, psgi.streaming
- Streams: psgi.input, psgi.errors
Plack Components (1)
- HTTP::Server::PSGI - reference PSGI web server
- plackup - CLI utility for starting PSGI apps
- Plack::Handler::* - connects PSGI apps with web servers,
- e.g. Plack::Handler::CGI, ::FCGI, ::Apache1, ::Apache2
Plack Components (2)
Lots of Plack::Middleware::* modules:
AccessLog AccessLog::Timed Auth::Basic
BufferedStreaming Chunked ConditionalGET
Conditional ContentLength ContentMD5
ErrorDocument Head HTTPExceptions JSONP
LighttpdScriptNameFix Lint Log4perl LogDispatch
MethodOverride NullLogger RearrangeHeaders
Recursive Refresh Runtime SimpleContentFilter
SimpleLogger StackTrace Static Writer
XFramework XSendfile
Plack Components (3)
Plack::Builder - DSL for configuring middleware:
builder {
enable "Static",
root =>$imgdir, path => qr(^/img/);
enable "Auth::Basic",
authenticator=>\&check_auth;
$mojolicious_app;
};
Plack Components (4)
- Plack::Request, Plack::Response
- Consistent API for request/response objects across web
environments
- Mainly intended for framework developers
Plack Components (5)
Plack::Test: Unified interface for writing tests
Plack::App::* - readymade applications:
Cascade, Directory, File, URLMap, CGIBin,
FCGIDispatcher, PSGIBin, WrapCGI
Some Other Modules
- Plack::App::Proxy
- Plack::Middleware::Session
- Plack::Middleware::Debug
- Plack::Middleware::Cache
- Plack::Middleware::XSLT
Deployment
Two aspects of deployment in this context:
- PSGI app deployment: Web Servers with PSGI support
- PSGI/Plack as a means of deployment: Web Frameworks
Plack Web Servers (1)
- Starman: HTTP 1.1, preforking, very fast, used by mixi.jp
- Twiggy: fast, non-blocking, based on AnyEvent
- Starlet: HTTP 1.0, preforking, fast
- Corona: coroutine-based
- HTTP::Server::Simple::PSGI - (almost) no deps
Plack Web Servers (2)
- Feersum: extremely fast, based on EV/libev, new
- uWSGI
- evpsgi (based on libevent)
- Others: Perlbal, nginx (patch), mod_psgi
Plack Web Servers (3)
- "So what should I use?"
- Standalone app server with little static content: Use Starman
- Behind a reverse-proxying frontend which handles static content: Use Starman
- FastCGI may also be an option in such a situation: Use Plack::Handler::FCGI
- Apache 2 with mod_perl2: Use Plack::Handler::Apache2
- Comet-style app or extremely high concurrency: Use Twiggy or Feersum
Framework Support (1)
- Catalyst
- Jifty
- CGI::Application
- Mojo + Mojolicious
- Dancer
Framework support (2)
- Tatsumaki (compare Tornado)
- Continuity (compare Seaside)
- Microframeworks: Squatting, Web::Simple, Angelos, Ark, Schenker, Noe, Kamui,
WebNano, Piglet, ...
Middleware Example (1)
- Example of how easy it is to write a middleware module
- Let's add Edge Site Includes to Plack - see http://www.w3.org/TR/esi-lang
- Usage scenario: Varnish on production servers, Plack middleware module on
development machines
- Although fully working, this limited example will only handle the
<esi:include /> tag, and in fact only its src attribute
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
- PSGI and Plack have made astonishing progress in just over a year
- The PSGI spec has been stable at v. 1.03 since Oct 2009
- Plack is close to a 1.0 version with a stable API for all normal usage
- It clearly represents the future of Perl web programming
- If you haven't already, go to http://plackperl.org/ and have fun!