Plack::Middleware - Base class for easy-to-use PSGI middleware
package Plack::Middleware::Foo; use parent qw( Plack::Middleware ); sub call { my($self, $env) = @_; # Do something with $env # $self->app is the original app my $res = $self->app->($env); # Do something with $res return $res; } # then in app.psgi use Plack::Builder; my $app = sub { ... } # as usual builder { enable "Plack::Middleware::Foo"; enable "Plack::Middleware::Bar", %options; $app; };
Plack::Middleware is a utility base class to write PSGI middleware. All you have to do is to inherit from Plack::Middleware and then implement the callback call method (or the to_app method that would return the PSGI code reference) to do the actual work. You can use $self->app to call the original (wrapped) application.
call
to_app
$self->app
Your middleware object is created at the the PSGI application compile time and is persistent during the web server life cycle (unless it is a non-persistent environment such as CGI), so you should never set or cache per-request data like $env in your middleware object. See also "OBJECT LIFECYCLE" in Plack::Component.
$env
See Plack::Builder how to actually enable middleware in your .psgi application file using the DSL. If you do not like our builder DSL, you can also use the wrap method to wrap your application with a middleware:
wrap
use Plack::Middleware::Foo; my $app = sub { ... }; $app = Plack::Middleware::Foo->wrap($app, %options); $app = Plack::Middleware::Bar->wrap($app, %options);
The typical middleware is written like this:
package Plack::Middleware::Something; use parent qw(Plack::Middleware); sub call { my($self, $env) = @_; # pre-processing $env my $res = $self->app->($env); # post-processing $res return $res; }
The tricky thing about post-processing the response is that it could either be an immediate 3 element array ref, or a code reference that implements the delayed (streaming) interface.
Dealing with these two types of response in each piece of middleware is pointless, so you're recommended to use the response_cb wrapper function in Plack::Util when implementing a post processing middleware.
response_cb
my $res = $app->($env); Plack::Util::response_cb($res, sub { my $res = shift; # do something with $res; });
The callback function gets a PSGI response as a 3 element array reference, and you can update the reference to implement the post-processing.
package Plack::Middleware::Always500; use parent qw(Plack::Middleware); use Plack::Util; sub call { my($self, $env) = @_; my $res = $self->app->($env); Plack::Util::response_cb($res, sub { my $res = shift; $res->[0] = 500; return; }); }
In this example, the callback gets the $res and updates its first element (status code) to 500. Using response_cb makes sure that this works with the delayed response too.
$res
You're not required (and not recommended either) to return a new array reference - they will be simply ignored. You're suggested to explicitly return, unless you fiddle with the content filter callback (see below).
Similarly, note that you have to keep the $res reference when you swap the entire response.
Plack::Util::response_cb($res, sub { my $res = shift; $res = [ $new_status, $new_headers, $new_body ]; # THIS DOES NOT WORK return; });
This does not work, since assigning a new anonymous array to $res doesn't update the original PSGI response value. You should instead do:
Plack::Util::response_cb($res, sub { my $res = shift; @$res = ($new_status, $new_headers, $new_body); # THIS WORKS return; });
The third element of the PSGI response array ref is a body, and it could be either an arrayref or IO::Handle-ish object. The application could also make use of the $writer object if psgi.streaming is in effect. Dealing with these variants is again really painful, and response_cb can take care of that too, by allowing you to return a content filter as a code reference.
$writer
psgi.streaming
# replace all "Foo" in content body with "Bar" Plack::Util::response_cb($res, sub { my $res = shift; return sub { my $chunk = shift; return unless defined $chunk; $chunk =~ s/Foo/Bar/g; return $chunk; } });
The callback takes one argument $chunk and your callback is expected to return the updated chunk. If the given $chunk is undef, it means the stream has reached the end, so your callback should also return undef, or return the final chunk and return undef when called next time.
$chunk
Plack Plack::Builder Plack::Component
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.