Plack::Builder(3)
π NAME π
Plack::Builder β this is the Plack::Builder(3) man page, bestie, and it's all about the OO and DSL ways to enable Plack Middlewares π
β¨ SYNOPSIS β¨
# in .psgi
use Plack::Builder;
my $app = sub { ... };
builder {
enable "Deflater";
enable "Session", store => "File";
enable "Debug", panels => [ qw(DBITrace Memory Timer) ];
enable "+My::Plack::Middleware";
$app;
};
# use URLMap
builder {
mount "/foo" => builder {
enable "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);
$builder->add_middleware('Bar');
$builder->wrap($app);
π DESCRIPTION π
Okay so Plack::Builder hands you a cute little domain specific language (DSL) so you can wrap your app in Plack::Middleware subclasses without losing your mind π§. The middleware you wanna use should be built on top of Plack::Middleware as its base class for this DSL to work β it's giving inspired by Rack::Builder, iykyk.
So like, every time you call "enable" on some middleware, that middleware app gets pushed onto the stack inside the builder, and then the whole thing gets reversed when it actually creates the wrapped application handler. And "Plack::Middleware::" is added as a prefix by default. So:
builder {
enable "Foo";
enable "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 bestie: you're supposed to "enable" middleware from outer to inner. Periodt π
π₯ INLINE MIDDLEWARE π₯
Plack::Builder lets you code middleware inline using a nested code reference, which is honestly so iconic.
If the first argument to "enable" is a code reference, it gets passed an $app and it should return another code reference β which is a PSGI application that consumes $env at runtime. So:
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);
πΊοΈ URLMap support πΊοΈ
Plack::Builder has native support for Plack::App::URLMap via the "mount" method. Obsessed π«Ά
use Plack::Builder;
my $app = builder {
mount "/foo" => $app1;
mount "/bar" => builder {
enable "Foo";
$app2;
};
};
Go peek at Plack::App::URLMap's "map" method if you wanna know what they mean by all that. But with "builder" you can't use "map" as a DSL β for the obvious reason π.
NOTE: Once you use"mount"in your builder code, you have to use"mount"for all the paths, including the root path ("/"). No sneaking around it.
You can't have the default app sitting in the last line of "builder" like:
my $app = sub {
my $env = shift;
...
};
builder {
mount "/foo" => sub { ... };
$app; # THIS DOESN'T WORK
};
You'll get warnings saying your mount configuration is gonna be ignored π. Instead, use "mount "/" => ..." in that last line to set the default fallback app:
builder {
mount "/foo" => sub { ... };
mount "/" => $app;
}
Also note that the "builder" DSL returns a whole new PSGI application, which means:
"builder { ... }"should normally be the last statement of a.psgifile, because the return value of"builder"is the application that actually gets executed. Main character energy, honestly π- You can nest your
"builder"blocks, mixed with"mount"statements (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 in a new PSGI application which is located under "/foo" because of the outer "builder" block. Nested builders ate, no cap β¨
π¦ CONDITIONAL MIDDLEWARE SUPPORT π¦
You can use "enable_if" to conditionally enable middleware based on the runtime environment πΈ
builder {
enable_if { $_[0]->{REMOTE_ADDR} eq '127.0.0.1' } 'StackTrace', force => 1;
$app;
};
See Plack::Middleware::Conditional for the deets.
π OBJECT ORIENTED INTERFACE π
The object oriented interface supports the exact same functionality as the DSL version, just in a clearer interface β probably with more typing required, ngl π
# With mount
my $builder = Plack::Builder->new;
$builder->add_middleware('Foo', opt => 1);
$builder->mount('/foo' => $foo_app);
$builder->mount('/' => $root_app);
$builder->to_app;
# Nested builders. Equivalent to:
# builder {
# mount '/foo' => builder {
# enable 'Foo';
# $app;
# };
# mount '/' => $app2;
# };
my $builder_out = Plack::Builder->new;
my $builder_in = Plack::Builder->new;
$builder_in->add_middleware('Foo');
$builder_out->mount("/foo" => $builder_in->wrap($app));
$builder_out->mount("/" => $app2);
$builder_out->to_app;
# conditional. You can also directly use Plack::Middleware::Conditional
my $builder = Plack::Builder->new;
$builder->add_middleware_if(sub { $_[0]->{REMOTE_ADDR} eq '127.0.0.1' }, 'StackTrace');
$builder->wrap($app);
β SEE ALSO β
Plack::Middleware Plack::App::URLMap Plack::Middleware::Conditional
and that's the whole vibe, bestie π go forth and enable your little heart out π
β¨ this was perl v5.42.3 from the User Contributed Perl Documentation, dated 2026-10-18 β Plack::Builder(3), signing off π«Ά
π¦ where this page comes from
- fedora 43: perl-Plack 1.0055-1.fc43 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- fedora 44: perl-Plack 1.0055-1.fc44 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms