PAGI-Server

Reference IO::Async server for the PAGI specification.

PAGI::Server is a reference implementation of a PAGI-compliant HTTP server. It speaks HTTP/1.1, WebSocket, and Server-Sent Events (with experimental HTTP/2), and prioritises spec compliance and code clarity over raw performance — it is the canonical reference for how a PAGI server should behave.

PAGI is an asynchronous Perl web-application interface in the spirit of Python's ASGI: an application is a coderef invoked with a scope, a receive callback, and a send callback. See the PAGI distribution for the specification itself.

Features

Installation

PAGI-Server requires Perl 5.18+. Install the dependencies with cpanm:

cpanm --installdeps .

Optional features need extra modules:

# TLS / HTTPS
cpanm IO::Async::SSL IO::Socket::SSL

# HTTP/2 (experimental)
cpanm Net::HTTP2::nghttp2

Future::IO is recommended so application code can sleep and do I/O without coupling to a specific event loop.

Quick start

A PAGI application is an async sub that receives ($scope, $receive, $send). Save this as app.pl:

use strict;
use warnings;
use Future::AsyncAwait;

my $app = async sub {
    my ($scope, $receive, $send) = @_;
    die "Unsupported scope type: $scope->{type}" if $scope->{type} ne 'http';

    await $send->({
        type    => 'http.response.start',
        status  => 200,
        headers => [ [ 'content-type', 'text/plain' ] ],
    });
    await $send->({
        type => 'http.response.body',
        body => 'Hello from PAGI',
        more => 0,
    });
};

$app;  # the file returns the coderef

Run it with the bundled pagi-server launcher:

pagi-server --app app.pl --port 5000
curl http://localhost:5000/
# => Hello from PAGI

Running programmatically

You can also drive PAGI::Server directly from your own event loop:

use IO::Async::Loop;
use PAGI::Server;

# If you use Future::IO-based libraries, load this BEFORE them:
use Future::IO::Impl::IOAsync;

my $loop   = IO::Async::Loop->new;
my $server = PAGI::Server->new(
    app  => $app,
    host => '127.0.0.1',
    port => 5000,
);

$loop->add($server);
$server->listen->get;  # start accepting connections

Command-line usage

pagi-server [options] [app] [key=value ...]

# Serve a PAGI app file
pagi-server ./app.pl

# Multi-worker, custom port
pagi-server --workers 4 --port 8080 ./app.pl

# Development mode (auto-enables Lint middleware when PAGI-Tools is installed)
pagi-server -E development ./app.pl

# HTTPS
pagi-server --ssl-cert cert.pem --ssl-key key.pem ./app.pl

# HTTP/2 over TLS (experimental)
pagi-server --http2 --ssl-cert cert.pem --ssl-key key.pem ./app.pl

Run perldoc pagi-server for the full list of options (workers, timeouts, limits, watermarks, TLS, listeners, and more).

Examples

The examples/ directory contains progressively more advanced, runnable applications — minimal HTTP, streaming with disconnect handling, request-body draining, a WebSocket echo server, an SSE broadcaster, lifespan/shared-state, extension-aware streaming, TLS introspection, a job runner, UTF-8 handling, and a backpressure test harness. Each has its own README.md. Start with examples/01-hello-http.

Documentation

Relationship to PAGI and PAGI-Tools

PAGI-Server has no runtime dependency on other PAGI distributions — the application runner (PAGI::Server::Runner) ships here. The framework-level toolkit (routers, endpoints, middleware such as PAGI::Middleware::Lint, and the PAGI::App::* apps) lives in the separate PAGI-Tools distribution and is used only when present. The specification itself lives in the PAGI distribution.

This distribution was split out of the PAGI distribution; its git history is preserved from the original repository.

License

Copyright (C) John Napiorkowski.

This library is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0.