Skip to content
GitHub

API Reference

Wraps the next step in the pipeline.

Interceptors use this to continue processing to the next interceptor or to the actual handler.

handle
async def handle() -> Any

Continue processing the request.

Returns the result of the next handler in the pipeline.


Provides access to web configuration.

Consumers that need configuration details should depend on this protocol for minimal coupling to the provider.

web_config
property web_config() -> Any

Return the web-layer configuration.

Returns
TypeDescription
AnyWebConfig instance with web-layer settings.
provider_config
property provider_config() -> Any

Return the provider-specific configuration.

Returns
TypeDescription
AnyWebProviderConfig instance with provider settings.
debug_routes_auth
property debug_routes_auth() -> Any

Return the debug routes authentication handler, if set.

Returns
TypeDescription
AnyCallable or None.
fail_on_route_conflict
property fail_on_route_conflict() -> bool

Whether to raise on duplicate route registration.

Returns
TypeDescription
boolTrue if duplicate routes should raise RuntimeError.

Provides the list of registered controller classes.

Consumers that only need access to controllers should depend on this protocol instead of the full WebProvider.

controllers
property controllers() -> list[type]

Return the list of registered controller classes.

Returns
TypeDescription
list[type]A list of controller class types.

Provides metadata about the current request being processed.

Used by interceptors and guards to access request information and make decisions about how to process the request/response.

request
property request() -> Any

The current HTTP request.

handler
property handler() -> Callable[Ellipsis, Any]

The handler function that will be called.

controller_class
property controller_class() -> type | None

The controller class, if this is a controller method.

method_name
property method_name() -> str | None

The name of the method being called.

route_metadata
property route_metadata() -> dict[str, Any]

Metadata about the route.


Transforms or validates a single handler parameter.

Pipes operate on individual parameters before they reach the handler. They can transform (e.g., parse string to int) or validate (e.g., check that a value is within range).

Example

class ParseIntPipe:
async def transform(self, value: Any, metadata: ParamMetadata) -> int:
if value is None:
return metadata.default or 0
try:
return int(value)
except ValueError:
raise BadRequestError(f"Invalid integer for {metadata.name}")
transform
async def transform(
    value: Any,
    metadata: ParamMetadata
) -> Any

Transform or validate the value.

Parameters
ParameterTypeDescription
`value`AnyThe value to transform/validate.
`metadata`ParamMetadataMetadata about the parameter.
Returns
TypeDescription
AnyThe transformed value.
Raises
ExceptionDescription
ExceptionOn validation failure (typically HTTP 400 Bad Request).

Provides access to internal provider resources.

Used by advanced components like routing and middleware managers that need direct access to router and OpenAPI generator.

router
property router() -> Any

Return the internal Router instance.

Returns
TypeDescription
AnyRouter instance or None if not initialized.
openapi_generator
property openapi_generator() -> Any

Return the OpenAPI generator instance.

Returns
TypeDescription
AnyOpenAPIGenerator instance or None if not configured.

Provides access to the underlying Starlette application.

Consumers that only need the Starlette app should depend on this protocol instead of the full WebProvider, decoupling from the provider’s full interface.

starlette
property starlette() -> Any

Return the Starlette application instance.

Returns
TypeDescription
AnyThe Starlette ASGI application, or None if not yet initialized.

Intercepts request/response flow with full AOP control.

Interceptors wrap the entire request→handler→response lifecycle, enabling cross-cutting concerns like logging, caching, response transformation, and timing without modifying handler code.

Example

class TimingInterceptor(Interceptor):
async def intercept(
self, context: ExecutionContextProtocol, next: CallHandlerProtocol
) -> Any:
start = time.perf_counter()
result = await next.handle()
elapsed = time.perf_counter() - start
return result
intercept
async def intercept(
    context: ExecutionContextProtocol,
    next_handler: CallHandlerProtocol
) -> Any

Intercept the request/response flow.

Parameters
ParameterTypeDescription
`context`ExecutionContextProtocolProvides metadata about the current request.
`next_handler`CallHandlerProtocolWraps the next step in the pipeline.
Returns
TypeDescription
AnyThe result of the handler (possibly transformed).

Notes: - MUST call await next_handler.handle() to continue the pipeline. - CAN transform the result before returning. - CAN add/modify response headers. - CAN short-circuit by returning early without calling next.


Combined protocol for full WebProvider access.

This is the complete interface expected by components that need the full capabilities of WebProvider. Consumers that need fewer properties should depend on the more specific protocols above to reduce coupling.


Metadata attached to a versioned controller or handler by ``@api_version``.
url_prefix
property url_prefix() -> str

Return the URL prefix for this version.


Accumulates background tasks to run after response is sent.

Context is captured at add time using propagate_context so that _execute_all restores the request-scope context variables (request_id, trace_id, …) even when called after the original request scope has been torn down.

__init__
def __init__() -> None
add
def add(
    func: Callable[Ellipsis, Any],
    *args: Any,
    **kwargs: Any
) -> None

Add a task to be executed after the response.

The current contextvars context is snapshotted immediately so that _execute_all can restore it at execution time.


Controller with built-in CQRS command and query bus dispatch.

Subclass this instead of Controller when your endpoints need to dispatch commands or queries through the CQRS buses.

The buses are injected via the constructor and are expected to be resolved from the DI container.

Example

class OrderController(CQRSController):
@post("/orders")
async def create_order(self, request: Request) -> JSONResponse:
data = await request.json()
result = await self.dispatch_command(CreateOrderCommand(**data))
return JSONResponse({"id": result.id}, status_code=201)
@get("/orders/{order_id}")
async def get_order(self, request: Request) -> JSONResponse:
order_id = request.path_params["order_id"]
result = await self.dispatch_query(GetOrderQuery(order_id=order_id))
return JSONResponse(result.to_dict())
class OrderController(CQRSController):
@post("/orders")
async def create_order(self, request: Request) -> JSONResponse:
data = await request.json()
result = await self.dispatch_command(CreateOrderCommand(**data))
return JSONResponse({"id": result.id}, status_code=201)
@get("/orders/{order_id}")
async def get_order(self, request: Request) -> JSONResponse:
order_id = request.path_params["order_id"]
result = await self.dispatch_query(GetOrderQuery(order_id=order_id))
return JSONResponse(result.to_dict())
__init__
def __init__(
    command_bus: CommandBusProtocol | None = None,
    query_bus: QueryBusProtocol | None = None
) -> None

Initialize CQRSController with optional command and query buses.

Parameters
ParameterTypeDescription
`command_bus`CommandBusProtocol | NoneCommandBusProtocol implementation for dispatching commands. If None, calling ``dispatch_command`` will raise RuntimeError.
`query_bus`QueryBusProtocol | NoneQueryBusProtocol implementation for executing queries. If None, calling ``dispatch_query`` will raise RuntimeError.
dispatch_command
async def dispatch_command(command: Any) -> Any

Dispatch a command through the command bus.

Parameters
ParameterTypeDescription
`command`AnyThe command object to dispatch.
Returns
TypeDescription
AnyThe result returned by the command handler.
Raises
ExceptionDescription
RuntimeErrorIf no CommandBusProtocol was provided to this controller.
dispatch_query
async def dispatch_query(query: Any) -> Any

Dispatch a query through the query bus.

Parameters
ParameterTypeDescription
`query`AnyThe query object to execute.
Returns
TypeDescription
AnyThe query result.
Raises
ExceptionDescription
RuntimeErrorIf no QueryBusProtocol was provided to this controller.

Base controller class with dependency injection support.

Controllers group related route handlers and can specify dependencies to be injected by the DI container.

Example

class UserController(Controller): @get(“/users”) async def list_users(self): return []

__init__
def __init__() -> None
collect_routes
def collect_routes(cls) -> list[dict[str, Any]]

Collect routes from controller methods.

It scans the class and its base classes for methods with _route_config attribute and returns a list of route definitions.

Returns
TypeDescription
List of route dictionaries with keysmethod, path, handler_name, etc.

Registry for managing controller registrations.

Canonical source for controllers: ControllerRegistry. Use ControllerRegistry for controller-level operations (class registration). Use RouteRegistry for route-level operations (path, method, handler).

__init__
def __init__() -> None
register
def register(
    key: str | type,
    value: type | None = None,
    *,
    allow_overwrite: bool | None = None
) -> type | Any

Register a controller class.

Parameters
ParameterTypeDescription
`key`str | typeComponent key or class
`value`type | NoneThe controller class to register
`allow_overwrite`bool | NoneWhether to allow overwriting an existing registration
Returns
TypeDescription
type | AnyThe registered controller class
get
def get(name: str) -> type | None

Get a controller class by name.

list_controllers
def list_controllers() -> list[str]

List all registered controller names.

get_all_controllers
def get_all_controllers() -> list[type]

Get all registered controller classes.

clear
def clear() -> None

Clear all registrations.

Use in tests only to prevent test pollution between test cases.


Builds the default Lexigram middleware stack as an explicit, composable list.

Encapsulates the minimum set of middlewares that every Lexigram web application applies so users can see and extend it without magic.

WebProvider delegates to this class internally, ensuring that all code paths produce the same default stack.

Parameters
ParameterTypeDescription
`container`The resolved DI container. Required for DIScopeMiddleware which provides request-scoped dependency resolution.
`extra_middlewares`Additional user-supplied Lexigram middlewares to include in the stack. They are adapted to Starlette ``Middleware`` wrappers via MiddlewareAdapterRegistry and inserted before the built-in defaults.

Example

from lexigram.web.middleware import DefaultMiddlewareStack
from lexigram.logging import get_logger
logger = get_logger(__name__)
# Inspect the default stack
stack = DefaultMiddlewareStack(container=container)
for mw in stack.build():
logger.debug("middleware", name=mw.cls.__name__)
# Extend with custom middleware
stack = DefaultMiddlewareStack(
container=container,
extra_middlewares=[MyTimingMiddleware()],
)
from lexigram.web.middleware import DefaultMiddlewareStack
from lexigram.logging import get_logger
logger = get_logger(__name__)
# Inspect the default stack
stack = DefaultMiddlewareStack(container=container)
for mw in stack.build():
logger.debug("middleware", name=mw.cls.__name__)
# Extend with custom middleware
stack = DefaultMiddlewareStack(
container=container,
extra_middlewares=[MyTimingMiddleware()],
)
__init__
def __init__(
    container: ContainerResolverProtocol | None = None,
    extra_middlewares: list[Any] | None = None
) -> None

Initialise the stack builder.

Parameters
ParameterTypeDescription
`container`ContainerResolverProtocol | NoneResolved DI container for ``DIScopeMiddleware``.
`extra_middlewares`list[Any] | NoneOptional extra Lexigram middlewares to include.
build
def build() -> list[StarletteMiddleware]

Build and return the ordered list of default Starlette middlewares.

The always-present entry is DIScopeMiddleware. Any extra_middlewares supplied at construction time are prepended to that entry after adaptation.

Returns
TypeDescription
list[StarletteMiddleware]An ordered list of starlette.middleware.Middleware instances ready to pass to starlette.applications.Starlette.

__init__
def __init__(error: E) -> None
is_ok
def is_ok() -> bool
is_err
def is_err() -> bool
unwrap
def unwrap() -> T
unwrap_err
def unwrap_err() -> E
unwrap_or
def unwrap_or(default: T) -> T
unwrap_or_else
def unwrap_or_else(op: Callable[[E], T]) -> T
map_sync
def map_sync(op: Callable[[T], U]) -> Result[U, E]
map_err
def map_err(op: Callable[[E], F]) -> Result[T, F]
and_then_sync
def and_then_sync(op: Callable[[T], Result[U, E]]) -> Result[U, E]
or_else_sync
def or_else_sync(op: Callable[[E], Result[T, F]]) -> Result[T, F]
expect
def expect(message: str) -> T
match
def match(
    ok: Callable[[T], U],
    err: Callable[[E], U]
) -> U
map
async def map(op: Callable[[T], Awaitable[U]]) -> Result[U, E]
async_map
async def async_map(op: Callable[[T], Awaitable[U]]) -> Result[U, E]

Alias for map — exists for backward compatibility.

and_then
async def and_then(op: Callable[[T], Awaitable[Result[U, E]]]) -> Result[U, E]
or_else
async def or_else(op: Callable[[E], Awaitable[Result[T, F]]]) -> Result[T, F]
flatten
def flatten() -> Result[Any, E]
filter
def filter(
    predicate: Callable[[T], bool],
    error: E
) -> Result[T, E]
ok_or
def ok_or(default: U) -> U

JSON response using lexigram common JSON utilities.

Uses orjson when available (5-10x faster than stdlib json) with graceful fallback to stdlib json. Provides consistent JSON serialization across all Lexigram packages.

Performance benefits:

  • 5-10x faster than stdlib json when orjson is available
  • Native datetime/UUID/dataclass support
  • Efficient bytes output
  • Consistent behavior across packages

For Pydantic models, prefer model.model_dump_json() which uses Rust-based serialization (similar performance to orjson).

render
def render(content: Any) -> bytes

File response for serving static files

Generic controller with common CRUD patterns for any service.

Returns Result[T, DomainError] from all action methods. The ResponseSerializer in the request pipeline automatically maps:

  • Ok(value) → 200 JSON response (201 for create_item).
  • Err(error) → HTTP error via ResultResponseMapper.

Use @error_status on your domain error classes to control the HTTP status code they map to

from lexigram.web import error_status
@error_status(404)
class ItemNotFound(DomainError): ...
from lexigram.web import error_status
@error_status(404)
class ItemNotFound(DomainError): ...
__init__
def __init__(
    service: CRUDServiceProtocol[T],
    resource_name: str | None = None
) -> None
resource_name
property resource_name() -> str

Get the resource name for permissions and error messages.

logger
property logger() -> Any

Get the logger for this controller.

list_items
async def list_items(
    limit: int = 20,
    offset: int = 0,
    **filters: Any
) -> Result[dict[str, Any], DomainError]

List items with pagination.

Returns a Result whose Ok payload is a dict with keys items, limit, offset, and total.

get_item
async def get_item(item_id: str) -> Result[T, DomainError]

Get single item by ID.

create_item
async def create_item(data: dict[str, Any]) -> Any

Create new item (returns 201 on success).

update_item
async def update_item(
    item_id: str,
    data: dict[str, Any]
) -> Result[T, DomainError]

Update existing item.

delete_item
async def delete_item(item_id: str) -> Any

Delete item (returns 204 on success).


Marker type explicitly indicating HTML content.

Handlers that return HTMLContent are explicitly declaring that the returned string should be treated as HTML. This avoids heuristic checks and makes the behavior explicit for callers.


HTML response
__init__
def __init__(
    content: Any = None,
    status_code: int = 200,
    headers: dict[str, str] | None = None,
    media_type: str | None = None,
    background: Any | None = None
) -> None

Convenience HTML response with HTMX-specific headers support.

Example

return HTMXResponse(“

ok
”, hx_trigger={“showToast”: “Saved”}) This will set the HX-Trigger header to the JSON-encoded value.

__init__
def __init__(
    content: Any,
    status_code: int = 200,
    headers: dict[str, str] | None = None,
    hx_trigger: Any = None,
    hx_refresh: bool = False
) -> None

ASGI middleware that sanitizes query string parameters.

Strips null bytes and rejects obvious script-injection patterns from query parameters before they reach request handlers. Path parameters are not modified because they have been parsed and validated by the router before they hit middleware.

This is a defense-in-depth measure, not a substitute for validation at the service layer.

Parameters
ParameterTypeDescription
`app`The ASGI application to wrap.
`sanitize_query_params`Whether to sanitize query string values (default: ``True``).
__init__
def __init__(
    app: Any,
    sanitize_query_params: bool = True
) -> None

JSON response with high performance.

Uses lexigram common JSON utilities for consistent serialization across all Lexigram packages. Automatically uses Pydantic’s Rust serializer for Pydantic models when available.

__init__
def __init__(
    content: Any = None,
    status_code: int = 200,
    headers: dict[str, str] | None = None,
    media_type: str | None = None,
    background: Any | None = None
) -> None

__init__
def __init__(value: T) -> None
is_ok
def is_ok() -> bool
is_err
def is_err() -> bool
unwrap
def unwrap() -> T
unwrap_err
def unwrap_err() -> E
unwrap_or
def unwrap_or(default: T) -> T
unwrap_or_else
def unwrap_or_else(op: Callable[[E], T]) -> T
map_sync
def map_sync(op: Callable[[T], U]) -> Result[U, E]
map_err
def map_err(op: Callable[[E], F]) -> Result[T, F]
and_then_sync
def and_then_sync(op: Callable[[T], Result[U, E]]) -> Result[U, E]
or_else_sync
def or_else_sync(op: Callable[[E], Result[T, F]]) -> Result[T, F]
expect
def expect(message: str) -> T
match
def match(
    ok: Callable[[T], U],
    err: Callable[[E], U]
) -> U
map
async def map(op: Callable[[T], Awaitable[U]]) -> Result[U, E]
async_map
async def async_map(op: Callable[[T], Awaitable[U]]) -> Result[U, E]

Alias for map — exists for backward compatibility.

and_then
async def and_then(op: Callable[[T], Awaitable[Result[U, E]]]) -> Result[U, E]
or_else
async def or_else(op: Callable[[E], Awaitable[Result[T, F]]]) -> Result[T, F]
flatten
def flatten() -> Result[Any, E]
filter
def filter(
    predicate: Callable[[T], bool],
    error: E
) -> Result[T, E]
ok_or
def ok_or(default: U) -> T

Metadata about a parameter being piped.

Attributes: name: The parameter name. param_type: The type of parameter (path, query, body, header, cookie, file). expected_type: The expected Python type for the parameter. default: Default value if the parameter is not provided. alias: Optional alias for the parameter.


RFC 7807 Problem Details for HTTP APIs.

Attributes: type: URI identifying the problem type title: Short summary of the problem status: HTTP status code detail: Human-readable explanation instance: URI for this specific occurrence errors: Additional validation errors (extension)

to_dict
def to_dict() -> dict[str, Any]

Convert to dictionary for JSON serialization.

from_exception
def from_exception(
    cls,
    exc: Exception,
    status: int = 500,
    debug: bool = False,
    **kwargs
) -> ProblemDetail

Create a ProblemDetail from an exception.

When debug is False (default), server-error responses (5xx) use a generic detail string to prevent internal information from leaking to API consumers. Set debug=True only in development environments.

validation_error
def validation_error(
    cls,
    errors: list[dict[str, Any]],
    detail: str = 'Validation failed'
) -> ProblemDetail

Create a validation error ProblemDetail.

not_found
def not_found(
    cls,
    resource: str,
    identifier: str | None = None
) -> ProblemDetail

Create a not found ProblemDetail.

bad_request
def bad_request(
    cls,
    detail: str,
    errors: list[dict[str, Any]] | None = None
) -> ProblemDetail

Create a bad request ProblemDetail.

internal_error
def internal_error(
    cls,
    detail: str = 'An internal error occurred'
) -> ProblemDetail

Create an internal error ProblemDetail.


Module-level rate limiting configuration.

Registers a RateLimitProvider in the application’s DI container so that route-level @throttle and @rate_limit decorators can resolve a limiter from the container.

Usage

app.add_module(RateLimitModule.configure(
backend="redis",
default_limit="100/minute",
))
# Development / testing — no external service required:
app.add_module(RateLimitModule.configure(backend="memory"))
app.add_module(RateLimitModule.configure(
backend="redis",
default_limit="100/minute",
))
# Development / testing — no external service required:
app.add_module(RateLimitModule.configure(backend="memory"))
configure
def configure(
    cls,
    *,
    backend: Literal['redis', 'memory'] = 'memory',
    default_limit: str | None = None,
    redis_client: Any = None
) -> Any

Create a DynamicModule that wires up rate limiting.

Parameters
ParameterTypeDescription
`backend`Literal['redis', 'memory']Storage backend. ``"redis"`` uses atomic Lua scripts (recommended for production); ``"memory"`` uses a process-local sliding window (suitable for development and single-process deployments).
`default_limit`str | NoneOptional default rate limit applied globally (not yet enforced by the module — provided for future middleware use). Accepts the same rate string format as throttle.
`redis_client`AnyPre-built Redis client. Only used when ``backend="redis"``. When *None*, the provider tries to resolve a ``"redis_client"`` binding from the container at boot time.
Returns
TypeDescription
AnyA DynamicModule descriptor.

Standalone provider for rate-limiting services.

Registers a RateLimiter in the DI container and lazily resolves a Redis client from the container at boot time when none is supplied at construction.

__init__
def __init__(
    redis_client: Any = None,
    enabled: bool = True
) -> None

Initialize rate limit provider.

Parameters
ParameterTypeDescription
`redis_client`AnyOptional pre-built Redis client for rate limiting.
`enabled`boolWhen ``False`` the provider skips all registration/boot.
register
async def register(container: ContainerRegistrarProtocol) -> None

Register rate limiter in the DI container.

Parameters
ParameterTypeDescription
`container`ContainerRegistrarProtocolDI container registrar.
boot
async def boot(container: ContainerResolverProtocol) -> None

Start the rate limit provider, resolving Redis from the container if needed.

shutdown
async def shutdown() -> None

Shutdown the rate limit provider.

health_check
async def health_check(timeout: float = 5.0) -> HealthCheckResult

Check rate-limit provider health.

Returns
TypeDescription
HealthCheckResultHealthCheckResult reflecting whether the limiter is initialised.

Redirect response

Lexigram request wrapper around Starlette request
__init__
def __init__(starlette_request: StarletteRequest)
method
property method() -> str
url
property url() -> Any
headers
property headers() -> Any
query_params
property query_params() -> dict[str, str]
cookies
property cookies() -> dict[str, str]
client
property client() -> Any

Client address information

app
property app() -> Any

Forward to the underlying Starlette app

session
property session() -> dict[str, Any]

Access the session state

path_params
property path_params() -> dict[str, Any]
json
async def json() -> Any
body
async def body() -> bytes
form
async def form() -> Any
state
property state() -> Any

Request state for middleware

scope
property scope() -> dict[str, Any]

Access the underlying ASGI scope

request
property request() -> StarletteRequest

Access the underlying Starlette request

user
property user() -> Any | None

Authenticated user set by auth middleware.

auth
property auth() -> Any | None

Authentication credentials.

request_id
property request_id() -> str | None

Request ID set by RequestIDMiddleware.

is_json
property is_json() -> bool

Check if request content type is JSON.

accepted_types
property accepted_types() -> list[str]

Parse Accept header into ordered list.

ip
property ip() -> str

Client IP address (proxy-aware).

validated_data
property validated_data() -> dict[str, Any]

Data validated/transformed by pipe pipeline.

validated_data
def validated_data(value: dict[str, Any]) -> None

Set validated data from pipe pipeline.


Base response class

Base Result type. Not abstract — Ok and Err are the only variants.
is_ok
def is_ok() -> bool
is_err
def is_err() -> bool
unwrap
def unwrap() -> T
unwrap_err
def unwrap_err() -> E
unwrap_or
def unwrap_or(default: T) -> T
unwrap_or_else
def unwrap_or_else(op: Callable[[E], T]) -> T
map_sync
def map_sync(op: Callable[[T], U]) -> Result[U, E]
map_err
def map_err(op: Callable[[E], F]) -> Result[T, F]
and_then_sync
def and_then_sync(op: Callable[[T], Result[U, E]]) -> Result[U, E]
or_else_sync
def or_else_sync(op: Callable[[E], Result[T, F]]) -> Result[T, F]
expect
def expect(message: str) -> T
match
def match(
    ok: Callable[[T], U],
    err: Callable[[E], U]
) -> U
map
async def map(op: Callable[[T], Awaitable[U]]) -> Result[U, E]
and_then
async def and_then(op: Callable[[T], Awaitable[Result[U, E]]]) -> Result[U, E]
or_else
async def or_else(op: Callable[[E], Awaitable[Result[T, F]]]) -> Result[T, F]
flatten
def flatten() -> Result[Any, E]
filter
def filter(
    predicate: Callable[[T], bool],
    error: E
) -> Result[T, E]
ok_or
def ok_or(default: U) -> T | U
from_exception
def from_exception(
    cls,
    exc: Exception,
    ok_type: type[T] = type(None)
) -> Result[T, Exception]

Wrap a caught exception into an Err result.

to_optional
def to_optional() -> T | None
inspect
def inspect(op: Callable[[T], None]) -> Result[T, E]
inspect_err
def inspect_err(op: Callable[[E], None]) -> Result[T, E]

Maps ``Result`` error values to HTTP responses.

The default mappings follow REST conventions:

Error typeStatus
NotFoundError404
ValidationError422
PermissionDeniedError403
AuthorizationError403
AuthenticationError401
ConflictError409
RateLimitError429
DomainError (base)400
other400
to_response
def to_response(
    result: Any,
    success_status: int = 200
) -> Response

Convert a Result to an HTTP response.

Parameters
ParameterTypeDescription
`result`AnyThe ``Result[T, E]`` object to map.
`success_status`intHTTP status code for Ok results (default 200).
Returns
TypeDescription
ResponseA JSONResponse with appropriate status code and structured body.
register
def register(
    cls,
    error_type: type[Exception],
    status_code: int
) -> None

Register a custom error type → HTTP status mapping.

Custom registrations take precedence over defaults (inserted at front).

Parameters
ParameterTypeDescription
`error_type`type[Exception]The exception class to match.
`status_code`intHTTP status code to return.
error_to_response
def error_to_response(
    cls,
    error: Any
) -> Response

Convert a domain error to a JSON HTTP response.

Parameters
ParameterTypeDescription
`error`AnyThe error value from ``Result.unwrap_err()``.
Returns
TypeDescription
ResponseA JSONResponse with the appropriate status code and a structured body.

GuardProtocol that checks if user has required role(s).

The authorizer must be injected at guard instantiation time (constructor injection).

Usage

__init__
def __init__(
    *required_roles: str,
    authorizer: AuthorizerProtocol
) -> None
can_activate
async def can_activate(context: Any) -> bool

Check if user has required role using AuthorizerProtocol.


Registry for managing route registrations and discovery.

Canonical source for routes: RouteRegistry. Use RouteRegistry for route-level operations (path, method, handler). Use ControllerRegistry for controller-level operations (class registration).

__init__
def __init__(debug: bool = False)
register_controller
def register_controller(
    controller_cls: type[Controller],
    controller_registry: ControllerRegistry | None = None
) -> None

Register a controller class and synchronize to ControllerRegistry.

Parameters
ParameterTypeDescription
`controller_cls`type[Controller]The controller class to register.
`controller_registry`ControllerRegistry | NoneIf provided, also registers the class by name in the ControllerRegistry for atomic synchronization. This ensures a controller exists in both registries, preventing lookup inconsistencies.
get_all_routes
def get_all_routes() -> dict[str, dict[str, Any]]

Get all registered routes

get_controllers
def get_controllers() -> list[type[Controller]]

Get all registered controllers

find_route
def find_route(
    path: str,
    method: str
) -> dict[str, Any] | None

Find a route by path and method

get_routes_by_controller
def get_routes_by_controller(controller_cls: type[Controller]) -> list[dict[str, Any]]

Get all routes for a specific controller

clear
def clear() -> None

Clear all registrations


Router with Controller DI Strategy support.

The Router manages route registration, controller resolution, and request handling. It integrates with the DI container to provide automatic dependency injection for controllers and their methods.

Attributes: routes: List of registered routes with their handlers. _controller_cache: Cache of resolved controller instances. _container: DI container for resolving dependencies. _signature_cache: Cache of handler signatures for performance. _routes_by_name: Dictionary of routes indexed by their unique name. exception_filters: Registry for handling controller exceptions.

__init__
def __init__(filter_pipeline: FilterPipeline | None = None)
get_route_by_name
def get_route_by_name(name: str) -> Route | None

Get a route by its unique name in O(1) time.

Parameters
ParameterTypeDescription
`name`strThe unique name of the route.
Returns
TypeDescription
Route | NoneThe Route object if found, otherwise None.
clear_cache
def clear_cache() -> None

Clear all cached handler signatures and type-hint lookups.

Call this when modules are hot-reloaded so that stale signatures are not used. The caches will be repopulated lazily on the next request that reaches each handler.

Example

hot_reload_manager.on_reload(router.clear_cache)
hot_reload_manager.on_reload(router.clear_cache)
add_route
def add_route(
    method: str,
    path: str,
    handler: Callable,
    name: str | None = None,
    controller_cls: type | None = None,
    **kwargs: Any
) -> None

Add a route (used internally)


Streaming response for large files or server-sent events

Extracts version from requests based on strategy.
__init__
def __init__(config: VersioningConfig)
extract
def extract(request: Request) -> str

Extract version from request.


Hierarchical root configuration for Lexigram Web.

This is the single source of truth for web configuration, loaded from application.yaml’s web section.

Attributes: name: Configuration name (default: “web”) enabled: Whether the web module is enabled server: Server binding and worker settings app: Application-level settings (OpenAPI, CORS origins, etc.) security: Security headers and policies cors: CORS configuration rate_limit: Rate limiting rules debug_routes: Enable /debug/* endpoints enable_identity_resolution: Resolve OAuth external IDs to internal UUIDs enable_auth: Enable built-in authentication middleware auth_exclude_paths: Paths excluded from authentication

validate_production_security
def validate_production_security() -> WebConfig

Block insecure configurations in production.


Base class for interceptors (optional convenience).

Provides a no-op implementation that subclasses can override.

intercept
async def intercept(
    context: ExecutionContextProtocol,
    next_handler: CallHandlerProtocol
) -> Any

Default implementation just passes through.


Web module with HTTP provider.
configure
def configure(
    cls,
    controllers: list[type] | None = None,
    discover: list[str] | tuple[str, Ellipsis] | None = None,
    host: str | None = None,
    port: int | None = None,
    **kwargs: Any
) -> DynamicModule

Create a WebModule with explicit configuration.

Configuration (CORS, CSRF, server host/port, etc.) is loaded from the [web] section of application.yaml by the orchestrator and injected into the provider at registration time. Pass a web_config kwarg only if you need to bypass YAML entirely.

Parameters
ParameterTypeDescription
`controllers`list[type] | NoneController classes to register with the web server.
`discover`list[str] | tuple[str, Ellipsis] | NonePackage paths to scan for controllers and merge with any explicitly provided controller classes.
`host`str | NoneOverride the server host (builds a ``WebConfig`` internally).
`port`int | NoneOverride the server port (builds a ``WebConfig`` internally). **kwargs: Additional keyword arguments forwarded to WebProvider.
stub
def stub(
    cls,
    config: Any = None
) -> DynamicModule

Return a no-op WebModule suitable for unit testing.

Registers WebProvider with no controllers and test-safe configuration. No real HTTP server is started.

Parameters
ParameterTypeDescription
`config`AnyOptional test configuration override.
Returns
TypeDescription
DynamicModuleA DynamicModule with in-memory web configuration.

Web provider with native Starlette integration and pass-through architecture.

Recommended usage — let the orchestrator inject configuration via application.yaml (uses config_key = "web" and config_model = WebConfig)

app.add_provider(WebProvider())
app.add_provider(WebProvider())

Config-first factory — construct from an explicit WebConfig

from lexigram.web import WebProvider, WebConfig
app.add_provider(WebProvider.from_config(WebConfig(debug=True, ...)))
from lexigram.web import WebProvider, WebConfig
app.add_provider(WebProvider.from_config(WebConfig(debug=True, ...)))

Advanced — pass individual components explicitly (e.g. for tests)

app.add_provider(WebProvider(
controllers=[UsersController],
middleware=[AuthMiddleware],
web_config=WebConfig(debug=True),
))
app.add_provider(WebProvider(
controllers=[UsersController],
middleware=[AuthMiddleware],
web_config=WebConfig(debug=True),
))

Note: The multi-parameter constructor is intended for advanced and test scenarios. For typical applications, prefer the no-arg or from_config() form so that configuration is driven by application.yaml.

__init__
def __init__(
    middleware: list[Any] | None = None,
    exception_handlers: dict[Any, Any] | None = None,
    controllers: list[type[Controller]] | None = None,
    web_config: WebConfig | None = None,
    provider_config: WebProviderConfig | None = None,
    debug_routes_auth: Callable[Ellipsis, Any] | None = None
) -> None
contributor_registry
property contributor_registry() -> Any

Expose contributor registry for route setup access.

from_config
def from_config(
    cls,
    config: WebConfig,
    **context: Any
) -> WebProvider

Create a WebProvider from config.

Context kwargs may include middleware, controllers, exception_handlers.

auto_discover
def auto_discover(
    cls,
    *packages: str,
    web_config: WebConfig | None = None,
    **kwargs: Any
) -> WebProvider

Create a WebProvider with controllers auto-discovered from packages.

Scans each package recursively for Controller subclasses and registers them automatically.

Parameters
ParameterTypeDescription
`web_config`WebConfig | NoneOptional web configuration. Falls back to defaults. **kwargs: Extra kwargs forwarded to WebProvider.__init__.
Returns
TypeDescription
WebProviderA configured WebProvider instance.

Example

app.add_provider(WebProvider.auto_discover("my_app.api.controllers"))
app.add_provider(WebProvider.auto_discover("my_app.api.controllers"))
register
async def register(container: ContainerRegistrarProtocol) -> None

Register web services in DI container

boot
async def boot(container: ContainerResolverProtocol) -> None

Initialize the web layer in five ordered phases.

Phase 1 — OpenAPI generator Instantiates OpenAPIGenerator with title and version from web_config.

Phase 2 — Starlette application Builds the native ASGI Starlette instance. The middleware stack is composed once here; it is never rebuilt at request time. Container and config are attached to app.state.

Phase 3 — Middleware pipeline Iterates registered AbstractMiddleware subclasses and wraps the Starlette app. Order follows the provider registration order (outermost-first).

Phase 4 — Integration setup Wires optional first-class integrations: authentication, rate limiting, GraphQL gateway. Each integration is only activated when its config key is present in the resolved container.

Phase 5 — Route registration Discovers annotated controller methods and mounts them on the Starlette router. Route-level dependencies (guards, interceptors, serializers) are resolved here.

shutdown
async def shutdown() -> None

Cleanup resources created by this provider.

health_check
async def health_check(timeout: float = 5.0) -> HealthCheckResult

Check web provider health.

run_server
def run_server(
    host: str = '127.0.0.1',
    port: int = 8000,
    **kwargs: Any
) -> None

Run the web application using Granian.

See lexigram.web.server.runner.run_server for implementation.


Payload fired when the ASGI server receives an incoming HTTP request.

Attributes: path: URL path of the incoming request (e.g. "/api/users"). method: HTTP verb in upper-case (e.g. "GET").


Payload fired once a response has been assembled, before it is sent.

Attributes: path: URL path the response belongs to. status_code: HTTP status code of the prepared response.


Payload fired after the ASGI lifespan ``startup`` phase completes.

Payload fired after an orderly ASGI lifespan ``shutdown`` completes.

Lexigram WebSocket wrapper around Starlette WebSocket
__init__
def __init__(starlette_ws: StarletteWebSocket)
accept
async def accept(subprotocol: str | None = None) -> None
close
async def close(code: int = 1000) -> None
receive_text
async def receive_text() -> str
receive_json
async def receive_json() -> Any
send_text
async def send_text(data: str) -> None
send_json
async def send_json(data: Any) -> None
send_bytes
async def send_bytes(data: bytes) -> None
state
property state() -> Any

WebSocket state for middleware


api_version
def api_version(
    ver: int | str,
    *,
    deprecated: bool = False,
    sunset: str | None = None,
    prefix: str | None = None
) -> Callable[[Any], Any]
Mark a controller (or individual handler) with an API version.

This extends the simpler version decorator with:

  • URL prefix — the version number is automatically prepended to the controller’s prefix attribute (e.g. prefix = "/users" becomes "/v1/users"). Override with the prefix argument.
  • Deprecation support — setting deprecated=True causes the routing layer to inject Deprecation: true and optionally Sunset: <date> response headers for all routes on the controller.
  • Metadata storage — an ApiVersionMetadata instance is stored on the class/function as __api_version_meta__ and the plain version string as __api_version__ (compatible with VersioningMiddleware).
Parameters
ParameterTypeDescription
`ver`int | strVersion number or string (e.g. ``1``, ``"2"``, ``"2.1"``).
`deprecated`boolWhen ``True``, mark this version as deprecated.
`sunset`str | NoneOptional ISO-8601 date string indicating when support ends.
`prefix`str | NoneExplicit URL prefix to use instead of the auto-derived one.
Returns
TypeDescription
Callable[[Any], Any]Class/function decorator.

Example

@api_version(1)
class UserControllerV1(Controller):
prefix = "/users" # mounted at /v1/users
@api_version(2)
class UserControllerV2(Controller):
prefix = "/users" # mounted at /v2/users
@api_version(1, deprecated=True, sunset="2025-12-31")
class LegacyController(Controller):
prefix = "/legacy" # adds Deprecation + Sunset headers
@api_version(1)
class UserControllerV1(Controller):
prefix = "/users" # mounted at /v1/users
@api_version(2)
class UserControllerV2(Controller):
prefix = "/users" # mounted at /v2/users
@api_version(1, deprecated=True, sunset="2025-12-31")
class LegacyController(Controller):
prefix = "/legacy" # adds Deprecation + Sunset headers

background
def background(func: Callable[Ellipsis, Awaitable[Any]]) -> Callable[Ellipsis, Awaitable[Any]]
Decorator to run a function as a background task.

body
def body(
    default: Any = ...,
    validation: Callable[Ellipsis, Any] | None = None,
    pipes: list[Any] | None = None
) -> Any
Request body parameter decorator.

controller
def controller(name: str | None = None) -> Any
Decorator to automatically register a controller class.
Parameters
ParameterTypeDescription
`name`str | NoneOptional controller name, defaults to class name

Example

@controller() class UserController(Controller): @get(“/users”) async def get_users(self): return {“users”: []}


cookie
def cookie(
    default: Any = ...,
    alias: str | None = None,
    validation: Callable[Ellipsis, Any] | None = None,
    pipes: list[Any] | None = None
) -> Any
Cookie parameter decorator.

delete
def delete(
    path: str,
    **kwargs: Any
) -> Any
Register a DELETE route handler.
Parameters
ParameterTypeDescription
`path`strURL path pattern for the route. **kwargs: Additional route configuration.
Returns
TypeDescription
AnyConfigured route handler function.

discover_controllers
def discover_controllers(packages: tuple[str, Ellipsis] | list[str]) -> list[type]
Scan packages for Controller subclasses and return the classes.
Parameters
ParameterTypeDescription
`packages`tuple[str, Ellipsis] | list[str]Dotted Python package paths to scan.
Returns
TypeDescription
list[type]List of Controller subclasses (not instantiated — the DI container constructs them during boot).

error_status
def error_status(
    error_type: type[Exception],
    status_code: int
) -> Any
Decorator to register a custom error → HTTP status mapping.
Parameters
ParameterTypeDescription
`error_type`type[Exception]Exception class to match.
`status_code`intHTTP status code to use.

Example

@error_status(PaymentDeclined, 402)
class BillingController(Controller):
...
@error_status(PaymentDeclined, 402)
class BillingController(Controller):
...

file
def file(
    default: Any = ...,
    validation: Callable[Ellipsis, Any] | None = None,
    pipes: list[Any] | None = None
) -> Any
File upload parameter decorator.

file_response
def file_response(
    path: str | Path,
    status_code: int = 200,
    headers: dict[str, str] | None = None,
    media_type: str | None = None,
    filename: str | None = None,
    content_disposition_type: str = 'attachment'
) -> FileResponse
Create a file response

form
def form(
    default: Any = ...,
    alias: str | None = None,
    validation: Callable[Ellipsis, Any] | None = None,
    pipes: list[Any] | None = None
) -> Any
Form parameter decorator.

get
def get(
    path: str,
    **kwargs: Any
) -> Any
Register a GET route handler.
Parameters
ParameterTypeDescription
`path`strURL path pattern for the route. **kwargs: Additional route configuration.
Returns
TypeDescription
AnyConfigured route handler function.

Example

@get("/users")
async def list_users(request):
return {"users": []}

get_current_user_optional
async def get_current_user_optional(request: Request) -> Any | None
Get current user from state (optional).

get_current_user_required
async def get_current_user_required(request: Request) -> Any
Get current user from state (required).

get_request_id
async def get_request_id(request: Request) -> str
Get request ID from state.

get_version
def get_version(request: Request) -> str
Get API version from request state.
Parameters
ParameterTypeDescription
`request`RequestThe HTTP request
Returns
TypeDescription
strAPI version string

guard
def guard(*guard_classes: type[Any] | Any) -> Any
Concise alias for use_guards.

Attaches one or more guards to a route handler or controller class. Guards are executed in order; the first failure returns a 403 response.

Parameters
ParameterTypeDescription
Returns
TypeDescription
AnyDecorator that attaches guards to the target.

Example

@guard(AuthGuard)
async def profile(self): ...
@guard(AuthGuard, PermissionGuard("users:write"))
async def create_user(self): ...
@guard(AuthGuard)
async def profile(self): ...
@guard(AuthGuard, PermissionGuard("users:write"))
async def create_user(self): ...

head
def head(
    path: str,
    **kwargs: Any
) -> Any
Register a HEAD route handler.
Parameters
ParameterTypeDescription
`path`strURL path pattern for the route. **kwargs: Additional route configuration.
Returns
TypeDescription
AnyConfigured route handler function.

header
def header(
    default: Any = ...,
    alias: str | None = None,
    validation: Callable[Ellipsis, Any] | None = None,
    pipes: list[Any] | None = None
) -> Any
Header parameter decorator.

html_response
def html_response(
    content: str,
    status_code: int = 200,
    headers: dict[str, str] | None = None
) -> HTMLResponse
Create an HTML response

injectable
def injectable(cls: type[T]) -> type[T]
Mark *cls* as transient and auto-register it in the quickstart container.

Each DI resolution creates a new instance of the class (transient scope). This is the quickstart alias for the transient-scope decorator.

Returns the class unchanged, so the decorator is transparent.

Parameters
ParameterTypeDescription
`cls`type[T]The class to register as a transient (per-resolve) service.
Returns
TypeDescription
type[T]The original *cls* with the injectable marker applied.

Example

from lexigram.web import app, get, injectable
from lexigram.logging import get_logger
logger = get_logger(__name__)
@injectable
class RequestLogger:
def log(self, msg: str) -> None:
logger.info("request_log", message=msg)
from lexigram.web import app, get, injectable
from lexigram.logging import get_logger
logger = get_logger(__name__)
@injectable
class RequestLogger:
def log(self, msg: str) -> None:
logger.info("request_log", message=msg)

json_response
def json_response(
    content: Any,
    status_code: int = 200,
    headers: dict[str, str] | None = None
) -> JSONResponse
Create a JSON response

options
def options(
    path: str,
    **kwargs: Any
) -> Any
Register an OPTIONS route handler.
Parameters
ParameterTypeDescription
`path`strURL path pattern for the route. **kwargs: Additional route configuration.
Returns
TypeDescription
AnyConfigured route handler function.

patch
def patch(
    path: str,
    **kwargs: Any
) -> Any
Register a PATCH route handler.
Parameters
ParameterTypeDescription
`path`strURL path pattern for the route. **kwargs: Additional route configuration.
Returns
TypeDescription
AnyConfigured route handler function.

path
def path(
    alias: str | None = None,
    validation: Callable[Ellipsis, Any] | None = None,
    pipes: list[Any] | None = None
) -> Any
Path parameter decorator.

post
def post(
    path: str,
    **kwargs: Any
) -> Any
Register a POST route handler.

Parameters annotated with a Pydantic BaseModel or DomainModel subclass are automatically deserialised from the JSON request body by ParameterBinder — no body() decorator is required.

Parameters
ParameterTypeDescription
`path`strURL path pattern for the route. **kwargs: Additional route configuration.
Returns
TypeDescription
AnyConfigured route handler function.

Example

@post("/users")
async def create_user(request):
data = await request.json()
return {"id": 1, "data": data}

put
def put(
    path: str,
    **kwargs: Any
) -> Any
Register a PUT route handler.
Parameters
ParameterTypeDescription
`path`strURL path pattern for the route. **kwargs: Additional route configuration.
Returns
TypeDescription
AnyConfigured route handler function.

query
def query(
    default: Any = ...,
    alias: str | None = None,
    validation: Callable[Ellipsis, Any] | None = None,
    pipes: list[Any] | None = None
) -> Any
Query parameter decorator.

redirect_response
def redirect_response(
    url: str,
    status_code: int = 302,
    headers: dict[str, str] | None = None
) -> RedirectResponse
Create a redirect response

register_controller
def register_controller(controller_cls: type[Controller]) -> None
Convenience function to register a controller.

Registers the controller in both RouteRegistry and ControllerRegistry, ensuring synchronization and preventing lookup inconsistencies.


render_template
def render_template(
    name: str,
    context: dict[str, Any] | None = None,
    templates: Jinja2Templates | None = None,
    **kwargs
) -> str

roles
def roles(
    *role_names: str,
    authorizer: Any | None = None
) -> Any
Restrict a handler to users that have at least one of the given roles.

The authorizer dependency must be injected.

Parameters
ParameterTypeDescription
`authorizer`Any | None**Required** AuthorizerProtocol instance, typically resolved from the container during application startup.
Returns
TypeDescription
AnyDecorator that attaches a RoleGuard to the target.

Example

authorizer = await container.resolve(AuthorizerProtocol)
@roles("admin", authorizer=authorizer)
async def admin_only(self): ...
@roles("admin", "moderator", authorizer=authorizer)
async def manage_content(self): ...
authorizer = await container.resolve(AuthorizerProtocol)
@roles("admin", authorizer=authorizer)
async def admin_only(self): ...
@roles("admin", "moderator", authorizer=authorizer)
async def manage_content(self): ...

singleton
def singleton(cls: type[T]) -> type[T]
Mark *cls* as a singleton and auto-register it in the quickstart container.

Combines the lexigram.di.singleton DI marker (which sets __lexigram_injectable__) with a direct entry in the quickstart service registry so the class is discovered regardless of whether it is defined at module scope.

Returns the class unchanged, so the decorator is transparent.

Parameters
ParameterTypeDescription
`cls`type[T]The class to register as a container-managed singleton.
Returns
TypeDescription
type[T]The original *cls* with the injectable marker applied.

Example

from lexigram.web import app, get, singleton
@singleton
class UserRepo:
async def find(self, user_id: str) -> dict:
return {"id": user_id}
from lexigram.web import app, get, singleton
@singleton
class UserRepo:
async def find(self, user_id: str) -> dict:
return {"id": user_id}

streaming_response
def streaming_response(
    content: AsyncGenerator[bytes, None] | Iterator[bytes],
    status_code: int = 200,
    headers: dict[str, str] | None = None,
    media_type: str | None = None
) -> StreamingResponse
Create a streaming response

throttle
def throttle(
    rate: str,
    *,
    by: Literal['user', 'ip', 'endpoint'] = 'user'
) -> Callable[[Any], Any]
Rate-limit a route handler using a human-readable rate string.

This is ergonomic sugar over the lower-level rate_limit decorator.

Parameters
ParameterTypeDescription
`rate`strRate string in ``"/"`` format, e.g. ``"30/minute"``, ``"5/hour"``, ``"100/second"``.
`by`Literal['user', 'ip', 'endpoint']Scope for the rate limit key: * ``"user"`` — per authenticated user (falls back to IP when ``request.state.user`` is not set). * ``"ip"`` — per client IP address. * ``"endpoint"`` — per route path + HTTP method.
Returns
TypeDescription
Callable[[Any], Any]Decorator that enforces the rate limit on the decorated handler.
Raises
ExceptionDescription
ValueErrorIf *rate* is not a valid rate string.

Example

@get("/search")
@throttle("30/minute")
async def search(self, request: Request) -> list[dict]: ...
@post("/upload")
@throttle("5/hour", by="user")
async def upload(self, request: Request) -> dict: ...
@get("/search")
@throttle("30/minute")
async def search(self, request: Request) -> list[dict]: ...
@post("/upload")
@throttle("5/hour", by="user")
async def upload(self, request: Request) -> dict: ...

trace
def trace(
    path: str,
    **kwargs: Any
) -> Any
Register a TRACE route handler.
Parameters
ParameterTypeDescription
`path`strURL path pattern for the route. **kwargs: Additional route configuration.
Returns
TypeDescription
AnyConfigured route handler function.

version
def version(api_version: str) -> Callable[[Any], Any]
Decorator to specify controller or method version.

Usage

@version("1")
class UsersController(Controller):
...
@version("2")
class UsersV2Controller(Controller):
...
@version("1")
class UsersController(Controller):
...
@version("2")
class UsersV2Controller(Controller):
...

websocket
def websocket(
    path: str,
    **kwargs: Any
) -> Any
Register a WebSocket route handler.
Parameters
ParameterTypeDescription
`path`strURL path pattern for the WebSocket endpoint. **kwargs: Additional route configuration.
Returns
TypeDescription
AnyConfigured WebSocket handler function.

websocket_handler
def websocket_handler(
    path: str,
    *,
    ping_interval: int | None = None,
    ping_timeout: int | None = None,
    max_connections_per_user: int | None = None
) -> Any
Decorator to mark a class as a WebSocket handler.

This decorator registers the handler class with the router and configures the WebSocket path.

Parameters
ParameterTypeDescription
`path`strURL path for the WebSocket endpoint (can include path parameters)
`ping_interval`int | NoneOverride default ping interval
`ping_timeout`int | NoneOverride default ping timeout
`max_connections_per_user`int | NoneOverride max connections per user

Example

@websocket_handler("/ws/chat/{room}")
class ChatHandler(AbstractWebSocketHandler):
async def on_connect(self, websocket):
await websocket.accept()
await self.broadcast({"type": "join", "user": "..."})
async def on_message(self, websocket, message):
await self.broadcast(message)
async def on_disconnect(self, websocket):
await self.broadcast({"type": "leave", "user": "..."})

409 Conflict.
__init__
def __init__(
    detail: str = 'Conflict',
    cause: Exception | None = None
) -> None

Base HTTP error, compatible with LexigramError.
__init__
def __init__(
    status_code: int,
    detail: str = '',
    headers: dict[str, str] | None = None,
    code: str | None = None,
    cause: Exception | None = None
) -> None

500 Internal Server Error.
__init__
def __init__(
    detail: str = 'Internal Server Error',
    code: str = 'INTERNAL_SERVER_ERROR',
    cause: Exception | None = None
) -> None

404 Not Found.
__init__
def __init__(
    detail: str = 'Not Found',
    cause: Exception | None = None
) -> None

429 Too Many Requests.
__init__
def __init__(
    detail: str = 'Too Many Requests',
    retry_after: int | None = None,
    cause: Exception | None = None
) -> None

503 Service Unavailable — connection limit reached.

Raised when a streaming endpoint (e.g. SSE) has reached its max_connections cap and cannot accept further connections.

__init__
def __init__(
    detail: str = 'Too many active connections',
    cause: Exception | None = None
) -> None