NAME
PAGI::Context - Per-request context with protocol-specific subclasses
SYNOPSIS
use PAGI::Context;
# Factory returns the right subclass based on scope type
my $ctx = PAGI::Context->new($scope, $receive, $send);
# Shared methods (all protocol types)
my $type = $ctx->type; # 'http', 'websocket', 'sse'
my $path = $ctx->path;
my $stash = $ctx->stash; # PAGI::Stash
my $session = $ctx->session; # PAGI::Session
# Protocol-specific (only on the appropriate subclass)
my $req = $ctx->request; # HTTP only
my $res = $ctx->response; # HTTP only
my $ws = $ctx->websocket; # WebSocket only
my $sse = $ctx->sse; # SSE only
DESCRIPTION
PAGI::Context is a factory and base class that provides a unified entry point for per-request context. Calling PAGI::Context->new(...) inspects $scope->{type} and returns the appropriate subclass: PAGI::Context::HTTP, PAGI::Context::WebSocket, or PAGI::Context::SSE.
Shared methods (scope accessors, stash, session, connection state) live on the base class. Protocol-specific methods (request/response, websocket, sse) live on subclasses and simply do not exist on other protocol types.
EXTENSIBILITY
Override _type_map to add or replace protocol types:
package MyApp::Context;
our @ISA = ('PAGI::Context');
sub _type_map {
my ($class) = @_;
return {
%{ $class->SUPER::_type_map },
grpc => 'MyApp::Context::GRPC',
};
}
Override _resolve_class for custom resolution logic beyond the type map.
CONSTRUCTOR
new
my $ctx = PAGI::Context->new($scope, $receive, $send);
Factory constructor. Returns a subclass instance based on $scope->{type}. Defaults to HTTP if type is missing or unknown.
CLASS METHODS
_type_map
my $map = PAGI::Context->_type_map;
Returns a hashref mapping scope type strings to subclass package names. Override in a subclass to add or replace protocol types.
_resolve_class
my $class = PAGI::Context->_resolve_class($scope);
Resolves the scope to a subclass package name. Looks up $scope->{type} in _type_map; defaults to the http mapping if the type is missing or unknown. Override for custom resolution logic.
METHODS
Scope Accessors
$ctx->scope; # raw $scope hashref
$ctx->type; # $scope->{type}
$ctx->path; # $scope->{path}
$ctx->raw_path; # $scope->{raw_path} // $scope->{path}
$ctx->query_string; # $scope->{query_string} // ''
$ctx->scheme; # $scope->{scheme} // 'http'
$ctx->client; # $scope->{client}
$ctx->server; # $scope->{server}
$ctx->headers; # $scope->{headers} arrayref of [name, value]
Path Parameters
my $params = $ctx->path_params; # hashref
my $id = $ctx->path_param('id'); # strict: dies if missing
my $id = $ctx->path_param('id', strict => 0); # returns undef
path_params returns the $scope->{path_params} hashref (set by the router), defaulting to {} if not present.
path_param returns a single parameter by name. By default it dies if the key is not found (strict mode). Pass strict => 0 to return undef for missing keys instead.
Protocol Introspection
$ctx->is_http; # true if type eq 'http'
$ctx->is_websocket; # true if type eq 'websocket'
$ctx->is_sse; # true if type eq 'sse'
header
my $value = $ctx->header('Content-Type');
Returns the last value for the named header (case-insensitive), or undef if not found.
receive
my $receive = $ctx->receive;
Returns the raw $receive coderef. Calling it returns a Future that resolves to the next protocol event hashref from the client.
# Read an HTTP request body event
my $event = await $ctx->receive->();
# $event = { type => 'http.request', body => '...' }
# Read a WebSocket message
my $msg = await $ctx->receive->();
# $msg = { type => 'websocket.receive', text => 'hello' }
Most users should prefer the protocol helpers ($ctx->request, $ctx->websocket, $ctx->sse) which handle the event protocol internally. Use receive only for raw protocol access.
send
my $send = $ctx->send;
Returns the raw $send coderef. Calling it with an event hashref returns a Future that resolves when the event has been sent.
# Send an HTTP response (two events: start + body)
await $ctx->send->({ type => 'http.response.start', status => 200,
headers => [['content-type', 'text/plain']] });
await $ctx->send->({ type => 'http.response.body', body => 'Hello' });
# Accept a WebSocket connection
await $ctx->send->({ type => 'websocket.accept' });
Most users should prefer the protocol helpers ($ctx->response, $ctx->websocket, $ctx->sse) which build and send events for you. Use send only for raw protocol access.
stash
my $stash = $ctx->stash; # PAGI::Stash instance
Returns a PAGI::Stash wrapping $scope->{'pagi.stash'}. Lazy-constructed and cached.
session
my $session = $ctx->session; # PAGI::Session instance
Returns a PAGI::Session wrapping $scope->{'pagi.session'}. Lazy-constructed and cached. Dies if session middleware has not run. Use has_session to check availability first.
has_session
if ($ctx->has_session) {
my $user_id = $ctx->session->get('user_id');
}
Returns true if session middleware has populated $scope->{'pagi.session'}.
state
my $state = $ctx->state; # hashref
Returns $scope->{state} — the app/endpoint-level shared state.
Connection State
$ctx->connection; # PAGI::Server::ConnectionState object
$ctx->is_connected; # boolean
$ctx->is_disconnected; # boolean
$ctx->disconnect_reason; # string or undef
$ctx->on_disconnect($cb); # register callback
Delegates to $scope->{'pagi.connection'}.
SEE ALSO
PAGI::Context::HTTP, PAGI::Context::WebSocket, PAGI::Context::SSE, PAGI::Stash, PAGI::Session
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 278:
Non-ASCII character seen before =encoding in '—'. Assuming UTF-8