.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32) .\" .\" 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 .. .if !\nF .nr F 0 .if \nF>0 \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} .\} .\" ======================================================================== .\" .IX Title "Plack::Builder 3pm" .TH Plack::Builder 3pm "2016-10-26" "perl v5.24.1" "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