Conditional middleware and URLMap app have something in common: they're PSGI applications but both takes PSGI application or middleware and dispatch them. This is the beauty of PSGI application and middleware architecture and today's application is another example of this.
Cascading multiple applications
Cascading can be useful if you have a couple of applications and runs in order, then try until it returns a successful response. This is sometimes called Chain of responsibility design pattern and often used in web applications such as mod_perl handlers.
Cascade Application
Plack::App::Cascade allows you to composite multiple applications in order and runs until it returns non-404 responses.
use Plack::App::Cascade;
use Plack::App::File;
use Plack::App::URLMap;
my @paths = qw(
/home/www/static
/virtualhost/example.com/htdocs/static
/users/miyagawa/public_html/images
);
my $app = Plack::App::Cascade->new;
for my $path (@paths) {
my $file = Plack::App::File->new(root => $path);
$app->add($file);
}
my $map = Plack::App::URLMap->new;
$map->mount("/static" => $app);
$map->to_app;
This application is mapped to /static
using URLMap, and all requests will try the three directories specified in @paths
using App::File application and returns the first found files. It might be useful if you want to serve static files but want to cascade from multiple directories like this.
Cascade different apps
use CatalystApp;
CatalystApp->setup_engine('PSGI');
my $app1 = sub { CatalystApp->run(@_) };
use CGI::Application::PSGI;
use CGIApp;
my $app2 = sub {
my $app = CGIApp->new({
QUERY => CGI::PSGI->new($_[0]),
});
CGI::Application::PSGI->run($app);
};
use Plack::App::Cascade;
Plack::App::Cascade->new(apps => [ $app1, $app2 ])->to_app;
This will create two applications, one with Catalyst and the other with CGI::Application and runs two applications in order. Suppose you have an overlapping URL structure and /what/ever.cat
served with the Catalyst application and /what/ever.cgiapp
served with the CGI::Application app.
Well that might sound crazy and i guess it's better to use URLMap to map two applications in different paths, but if you really want to cascade them, this is the way to go :)
There is no DSL for cascading, like there is for stacking middleware?
Posted by: Jakub Narebski | 12/20/2009 at 07:37 AM
Jakub: Good question: i've been thinking about it for a while but couldn't find a nice DSL to implement that yet. But yes that's the plan.
Posted by: miyagawa | 12/20/2009 at 10:12 AM
In the first example, shouldn't it say:
$app->add($file);
?
Posted by: Bernhard Schmalhofer | 12/24/2009 at 04:39 AM
Bernhard: Fixed. Thanks!
Posted by: miyagawa | 12/24/2009 at 07:07 AM