NAME
PAGI::Middleware::Builder - DSL for composing PAGI middleware
SYNOPSIS
use PAGI::Middleware::Builder;
# Functional DSL
my $app = builder {
enable 'ContentLength';
enable 'CORS', origins => ['*'];
enable_if { $_[0]->{path} =~ m{^/api/} } 'RateLimit', limit => 100;
mount '/static' => $static_app;
$my_app;
};
# Object-oriented interface
my $builder = PAGI::Middleware::Builder->new;
$builder->enable('ContentLength');
$builder->enable('CORS', origins => ['*']);
$builder->mount('/admin', $admin_app);
my $app = $builder->to_app($my_app);
DESCRIPTION
PAGI::Middleware::Builder provides a DSL for composing middleware into a PAGI application. It supports:
Enabling middleware with configuration
Conditional middleware application
Path-based routing (mount)
Middleware ordering
EXPORTS
builder
my $app = builder { ... };
Create a composed application using the DSL. The block should call enable(), enable_if(), mount(), and return the final app. The final value of the block is coerced via "to_app" in PAGI::Utils, so you can return a component object or class name directly:
my $app = builder {
enable 'ContentLength';
PAGI::App::NotFound->new;
};
enable
enable 'MiddlewareName', %config;
enable 'Auth::Basic', %config; # PAGI::Middleware::Auth::Basic
enable '^My::Custom::Middleware'; # My::Custom::Middleware (no prefix)
enable(PAGI::Middleware::GZip->new(level => 9)); # pre-configured instance
Enable a middleware. The name is automatically prefixed with 'PAGI::Middleware::' unless it starts with '^', which indicates a fully qualified class name (the '^' is stripped).
When passed an already-configured middleware instance (an object with a wrap method), it is used directly. Passing config args alongside an instance is an error — configure the instance at construction time.
The parentheses are required for the instance form: enable $obj without them is parsed as an indirect method call and dies with a confusing error.
enable_if
enable_if { $condition } 'MiddlewareName', %config;
enable_if { $condition } (PAGI::Middleware::GZip->new(level => 9));
Conditionally enable middleware. The condition block receives the scope and returns true/false. A pre-configured middleware instance may be passed instead of a class name; config args alongside an instance are an error.
mount
mount '/path' => $app;
mount '/static' => PAGI::App::File->new(root => $dir);
mount '/api' => 'MyApp::API';
Mount an application at a path prefix. Requests matching the prefix are routed to the mounted app with adjusted paths. The app argument accepts anything "to_app" in PAGI::Utils accepts: a coderef, a component object with to_app, or a class name.
METHODS
new
my $builder = PAGI::Middleware::Builder->new;
Create a new builder instance.
enable
$builder->enable('MiddlewareName', %config);
Add middleware to the stack (OO interface).
enable_if
$builder->enable_if(\&condition, 'MiddlewareName', %config);
Add conditional middleware to the stack (OO interface).
mount
$builder->mount('/path', $app);
Add a path-based mount point (OO interface).
to_app
my $app = $builder->to_app($inner_app);
Build the composed application. $inner_app accepts anything "to_app" in PAGI::Utils accepts: a coderef, a component object with to_app, or a class name. This means builder { ...; $router } and builder { ...; PAGI::App::NotFound-new }> work without an explicit ->to_app call.
MIDDLEWARE ORDERING
Middleware is applied in the order specified, with the first middleware being the outermost wrapper. This means:
builder {
enable 'A';
enable 'B';
enable 'C';
$app;
};
Results in: A wraps B wraps C wraps $app
Request flow: A -> B -> C -> app -> C -> B -> A
SEE ALSO
PAGI::Middleware - Base class for middleware