File: //usr/local/share/man/man3/Plack::Builder.3pm
.\" Automatically generated by Pod::Man 4.11 (Pod::Simple 3.35)
.\"
.\" Standard preamble:
.\" ========================================================================
.de Sp \" Vertical space (when we can't use .PP)
.if t .sp .5v
.if n .sp
..
.de Vb \" Begin verbatim text
.ft CW
.nf
.ne \\$1
..
.de Ve \" End verbatim text
.ft R
.fi
..
.\" Set up some character translations and predefined strings. \*(-- will
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
.\" nothing in troff, for use with C<>.
.tr \(*W-
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
.ie n \{\
. ds -- \(*W-
. ds PI pi
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
. ds L" ""
. ds R" ""
. ds C` ""
. ds C' ""
'br\}
.el\{\
. ds -- \|\(em\|
. ds PI \(*p
. ds L" ``
. ds R" ''
. ds C`
. ds C'
'br\}
.\"
.\" Escape single quotes in literal strings from groff's Unicode transform.
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\"
.\" If the F register is >0, we'll generate index entries on stderr for
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
.\" entries marked with X<> in POD. Of course, you'll have to process the
.\" output yourself in some meaningful fashion.
.\"
.\" Avoid warning from groff about undefined register 'F'.
.de IX
..
.nr rF 0
.if \n(.g .if rF .nr rF 1
.if (\n(rF:(\n(.g==0)) \{\
. if \nF \{\
. de IX
. tm Index:\\$1\t\\n%\t"\\$2"
..
. if !\nF==2 \{\
. nr % 0
. nr F 2
. \}
. \}
.\}
.rr rF
.\" ========================================================================
.\"
.IX Title "Plack::Builder 3"
.TH Plack::Builder 3 "2020-11-30" "perl v5.26.3" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
.nh
.SH "NAME"
Plack::Builder \- OO and DSL to enable Plack Middlewares
.SH "SYNOPSIS"
.IX Header "SYNOPSIS"
.Vb 2
\& # 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(\*(AqFoo\*(Aq, opt => 1);
\& $builder\->add_middleware(\*(AqBar\*(Aq);
\& $builder\->wrap($app);
.Ve
.SH "DESCRIPTION"
.IX Header "DESCRIPTION"
Plack::Builder gives you a quick domain specific language (\s-1DSL\s0) 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 \s-1DSL,\s0 inspired by Rack::Builder.
.PP
Whenever you call \f(CW\*(C`enable\*(C'\fR 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. \f(CW"Plack::Middleware::"\fR
is added as a prefix by default. So:
.PP
.Vb 5
\& builder {
\& enable "Foo";
\& enable "Bar", opt => "val";
\& $app;
\& };
.Ve
.PP
is syntactically equal to:
.PP
.Vb 2
\& $app = Plack::Middleware::Bar\->wrap($app, opt => "val");
\& $app = Plack::Middleware::Foo\->wrap($app);
.Ve
.PP
In other words, you're supposed to \f(CW\*(C`enable\*(C'\fR middleware from outer to inner.
.SH "INLINE MIDDLEWARE"
.IX Header "INLINE MIDDLEWARE"
Plack::Builder allows you to code middleware inline using a nested
code reference.
.PP
If the first argument to \f(CW\*(C`enable\*(C'\fR is a code reference, it will be
passed an \f(CW$app\fR and should return another code reference
which is a \s-1PSGI\s0 application that consumes \f(CW$env\fR at runtime. So:
.PP
.Vb 10
\& builder {
\& enable sub {
\& my $app = shift;
\& sub {
\& my $env = shift;
\& # do preprocessing
\& my $res = $app\->($env);
\& # do postprocessing
\& return $res;
\& };
\& };
\& $app;
\& };
.Ve
.PP
is equal to:
.PP
.Vb 4
\& my $mw = sub {
\& my $app = shift;
\& sub { my $env = shift; $app\->($env) };
\& };
\&
\& $app = $mw\->($app);
.Ve
.SH "URLMap support"
.IX Header "URLMap support"
Plack::Builder has a native support for Plack::App::URLMap via the \f(CW\*(C`mount\*(C'\fR method.
.PP
.Vb 8
\& use Plack::Builder;
\& my $app = builder {
\& mount "/foo" => $app1;
\& mount "/bar" => builder {
\& enable "Foo";
\& $app2;
\& };
\& };
.Ve
.PP
See Plack::App::URLMap's \f(CW\*(C`map\*(C'\fR method to see what they mean. With
\&\f(CW\*(C`builder\*(C'\fR you can't use \f(CW\*(C`map\*(C'\fR as a \s-1DSL,\s0 for the obvious reason :)
.PP
\&\fB\s-1NOTE\s0\fR: Once you use \f(CW\*(C`mount\*(C'\fR in your builder code, you have to use
\&\f(CW\*(C`mount\*(C'\fR for all the paths, including the root path (\f(CW\*(C`/\*(C'\fR). You can't
have the default app in the last line of \f(CW\*(C`builder\*(C'\fR like:
.PP
.Vb 4
\& my $app = sub {
\& my $env = shift;
\& ...
\& };
\&
\& builder {
\& mount "/foo" => sub { ... };
\& $app; # THIS DOESN\*(AqT WORK
\& };
.Ve
.PP
You'll get warnings saying that your mount configuration will be
ignored. Instead you should use \f(CW\*(C`mount "/" => ...\*(C'\fR in the last
line to set the default fallback app.
.PP
.Vb 4
\& builder {
\& mount "/foo" => sub { ... };
\& mount "/" => $app;
\& }
.Ve
.PP
Note that the \f(CW\*(C`builder\*(C'\fR \s-1DSL\s0 returns a whole new \s-1PSGI\s0 application, which means
.IP "\(bu" 4
\&\f(CW\*(C`builder { ... }\*(C'\fR should normally the last statement of a \f(CW\*(C`.psgi\*(C'\fR
file, because the return value of \f(CW\*(C`builder\*(C'\fR is the application that
is actually executed.
.IP "\(bu" 4
You can nest your \f(CW\*(C`builder\*(C'\fR blocks, mixed with \f(CW\*(C`mount\*(C'\fR statements (see \*(L"URLMap support\*(R"
above):
.Sp
.Vb 5
\& builder {
\& mount "/foo" => builder {
\& mount "/bar" => $app;
\& }
\& }
.Ve
.Sp
will locate the \f(CW$app\fR under \f(CW\*(C`/foo/bar\*(C'\fR, since the inner \f(CW\*(C`builder\*(C'\fR
block puts it under \f(CW\*(C`/bar\*(C'\fR and it results in a new \s-1PSGI\s0 application
which is located under \f(CW\*(C`/foo\*(C'\fR because of the outer \f(CW\*(C`builder\*(C'\fR block.
.SH "CONDITIONAL MIDDLEWARE SUPPORT"
.IX Header "CONDITIONAL MIDDLEWARE SUPPORT"
You can use \f(CW\*(C`enable_if\*(C'\fR to conditionally enable middleware based on
the runtime environment.
.PP
.Vb 4
\& builder {
\& enable_if { $_[0]\->{REMOTE_ADDR} eq \*(Aq127.0.0.1\*(Aq } \*(AqStackTrace\*(Aq, force => 1;
\& $app;
\& };
.Ve
.PP
See Plack::Middleware::Conditional for details.
.SH "OBJECT ORIENTED INTERFACE"
.IX Header "OBJECT ORIENTED INTERFACE"
Object oriented interface supports the same functionality with the \s-1DSL\s0
version in a clearer interface, probably with more typing required.
.PP
.Vb 6
\& # With mount
\& my $builder = Plack::Builder\->new;
\& $builder\->add_middleware(\*(AqFoo\*(Aq, opt => 1);
\& $builder\->mount(\*(Aq/foo\*(Aq => $foo_app);
\& $builder\->mount(\*(Aq/\*(Aq => $root_app);
\& $builder\->to_app;
\&
\& # Nested builders. Equivalent to:
\& # builder {
\& # mount \*(Aq/foo\*(Aq => builder {
\& # enable \*(AqFoo\*(Aq;
\& # $app;
\& # };
\& # mount \*(Aq/\*(Aq => $app2;
\& # };
\& my $builder_out = Plack::Builder\->new;
\& my $builder_in = Plack::Builder\->new;
\& $builder_in\->add_middleware(\*(AqFoo\*(Aq);
\& $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 \*(Aq127.0.0.1\*(Aq }, \*(AqStackTrace\*(Aq);
\& $builder\->wrap($app);
.Ve
.SH "SEE ALSO"
.IX Header "SEE ALSO"
Plack::Middleware Plack::App::URLMap Plack::Middleware::Conditional