Plack::Builder - OO and DSL to enable Plack Middlewares
# in .psgi use Plack::Builder; my $app = sub { ... }; builder { enable "Plack::Middleware::Foo"; enable "Plack::Middleware::Bar", opt => "val"; enable "Plack::Middleware::Baz"; $app; }; # use URLMap builder { mount "/foo" => builder { enable "Plack::Middleware::Foo"; $app; }; mount "/bar" => $app2; mount "http://example.com/" => builder { $app3 }; }; # using OO interface my $builder = Plack::Builder->new(); $builder->add_middleware('Foo', opt => 1); $app = $builder->mount('/app' => $app); $app = $builder->to_app($app);
Plack::Builder gives you a quick domain specific language (DSL) to wrap your application with Plack::Middleware subclasses. The middleware you're trying to use should use Plack::Middleware as a base class to use this DSL, inspired by Rack::Builder.
Whenever you call enable on any middleware, the middleware app is pushed to the stack inside the builder, and then reversed when it actually creates a wrapped application handler, so:
enable
builder { enable "Plack::Middleware::Foo"; enable "Plack::Middleware::Bar", opt => "val"; $app; };
is syntactically equal to:
$app = Plack::Middleware::Bar->wrap($app, opt => "val"); $app = Plack::Middleware::Foo->wrap($app);
In other words, you're supposed to enable middleware from outer to inner.
Plack::Builder allows you to code middleware inline using a nested code reference.
If the first argument to enable is a code reference, it will be passed an $app and is supposed to return another code reference which is PSGI application that consumes $env in runtime. So:
$app
$env
builder { enable sub { my $app = shift; sub { my $env = shift; # do preprocessing my $res = $app->($env); # do postprocessing return $res; }; }; $app; };
is equal to:
my $mw = sub { my $app = shift; sub { my $env = shift; $app->($env) }; }; $app = $mw->($app);
Plack::Builder has a native support for Plack::App::URLMap with mount method.
mount
use Plack::Builder; my $app = builder { mount "/foo" => $app1; mount "/bar" => builder { enable "Plack::Middleware::Foo"; $app2; }; };
See Plack::App::URLMap's map method to see what they mean. With builder you can't use map as a DSL, for the obvious reason :)
map
NOTE: Once you use mount in your builder code, you have to use mount for all the paths, including the root path (/). You can't have the default app in the last line of builder like:
/
builder
my $app = sub { my $env = shift; ... }; builder { mount "/foo" => sub { ... }; $app; # THIS DOESN'T WORK };
You'll get warnings saying that your mount configuration will be ignored. Instead you should use mount "/" => ... in the last line to set the default fallback app.
mount "/" => ...
builder { mount "/foo" => sub { ... }; mount "/" => $app; }
Note that the builder DSL returns a whole new PSGI application, which means
builder { ... } should normally the last statement of a .psgi file, because the return value of builder is the application that actually is executed.
builder { ... }
.psgi
You can nest your builder block, mixed with mount (see URLMap support above):
builder { mount "/foo" => builder { mount "/bar" => $app; } }
will locate the $app under /foo/bar since the inner builder block puts it under /bar and it results a new PSGI application which is located under /foo because of the outer builder block.
/foo/bar
/bar
/foo
You can use enable_if to conditionally enable middleware based on the runtime environment. See Plack::Middleware::Conditional for details.
enable_if
Plack::Middleware Plack::App::URLMap Plack::Middleware::Conditional
To install Plack, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Plack
CPAN shell
perl -MCPAN -e shell install Plack
For more information on module installation, please visit the detailed CPAN module installation guide.