Request
HTTP request handling and utilities.
Transport-agnostic request system.
- Classes:
- BaseRequest (ABC) — transport-agnostic interface
├── HttpRequest — ASGI HTTP (stream-based, body via receive) └── MsgRequest — WSX messages (atomic, WebSocket/NATS)
RequestRegistry — factory and tracking for active requests
Every request has an associated Response (request.response).
The handler returns a value; the Dispatcher calls
response.set_result() and sends the ASGI response.
Request/Response lifecycle:
RequestRegistry.create(scope, receive, send)
→ factory() # sync: allocate slots
→ request.init() # async: read body, parse data
→ register in registry
set_current_request(request)
router.node(path) → handler
result = handler(**request.query)
response.set_result(result)
response(scope, receive, send)
set_current_request(None)
registry.unregister()
- Notification pattern (fire-and-forget over HTTP):
Some protocols (e.g., JSON-RPC 2.0) define messages that expect no response payload. The handler sets the status code and returns None; the Dispatcher sends an empty HTTP response:
request = get_current_request() request.response.status_code = 202 return None # Dispatcher sends 202 with empty body
- class genro_asgi.request.BaseRequest[source]
Bases:
ABCAbstract base for transport-agnostic requests.
Subclasses: HttpRequest (ASGI HTTP), MsgRequest (WSX messages). Handlers see only BaseRequest and work identically across transports.
Every instance carries an associated
response(Response object). The handler controls the response viarequest.response: status code, headers, and — indirectly — body (the Dispatcher callsresponse.set_result()with whatever the handler returns).For notification/fire-and-forget over HTTP the handler sets
request.response.status_code = 202and returnsNone.- Abstract properties (subclasses must implement):
id, method, path, headers, cookies, query, data, transport
- Concrete attributes:
response: Associated Response object (created in __init__) auth_tags: Security tags injected by AuthMiddleware via scope env_capabilities: Environment flags injected via scope external_id: Client-provided correlation ID (optional) tytx_mode: True when request uses TYTX serialization tytx_transport: TYTX transport type (‘json’, ‘msgpack’) or None app_name: App handling this request (set after routing, for metrics) created_at: Timestamp (epoch) when request was created age: Seconds since creation (computed)
- add_cleanup(callback)[source]
Register a callback to run at end of request (always, even on error).
- abstractmethod async init(scope, receive, send=None, **kwargs)[source]
Async initialization — parse transport data from ASGI scope.
Subclasses must override to read body/message, populate internal state (headers, cookies, query, data), and extract auth context.
- Parameters:
scope (
MutableMapping[str,Any]) – ASGI scope dict.receive (
Callable[[],Awaitable[MutableMapping[str,Any]]]) – ASGI receive callable.send (
Optional[Callable[[MutableMapping[str,Any]],Awaitable[None]]]) – ASGI send callable (optional, not used by all transports).**kwargs (
Any) – Transport-specific options (e.g.server,websocket).
- Return type:
- run_cleanups(error=None)[source]
Run registered callbacks. Called by Dispatcher in finally block.
- Parameters:
error (
BaseException|None) – The exception if request failed, None on success.- Return type:
- class genro_asgi.request.HttpRequest[source]
Bases:
BaseRequestHTTP request adapter — wraps ASGI scope, parses body via asgi_data.
Supports both TYTX-encoded requests (type hydration for Decimal, date, datetime, time) and standard HTTP requests with plain JSON bodies.
TYTX mode is detected from the
X-TYTX-Transportheader. When present, Response uses the same transport to serialize the reply. Body parsing is handled bygenro_tytx.asgi_data()in both cases (after genro-tytx 0.8.0, plain JSON is parsed correctly without TYTX markers).- Parsing flow (in
init()): Headers decoded from ASGI scope (latin-1)
TYTX mode detected from X-TYTX-Transport header
asgi_data(scope, receive)parses headers, query, cookies, bodyRequest ID extracted from x-request-id header or generated (UUID)
Auth context read from scope (injected by AuthMiddleware)
- Known limitation:
Raw body bytes are not preserved after parsing.
asgi_dataconsumes the ASGI receive callable internally;self.bodyreturnsb"".- Extra properties (beyond BaseRequest):
scope, body, scheme, url, headers_obj, query_params, client, state, content_type
- property db: Any
Database connection, lazy-loaded from
scope["ctx"]._db.On first access, reads
ctx._db(set by Dispatcher) and registersdb.closeConnectionas a request cleanup callback.- Returns:
The database connection, or None if ctx is absent or has no
_db.
- property headers_obj: Headers
Request headers as Headers object (case-insensitive).
- async init(scope, receive, send=None, **kwargs)[source]
Async init — parse headers, body, query, cookies via asgi_data.
Delegates to
genro_tytx.asgi_data(scope, receive)which handles TYTX-encoded and plain JSON bodies transparently (since genro-tytx 0.8.0). After this method:self._data: parsed body (dict for JSON, None if empty/unparseable)self._headers,self._cookies,self._query: populatedself._tytx_mode: True if X-TYTX-Transport header was presentself._auth_tags,self._env_capabilities: from scopeself._body: b”” (raw bytes not preserved — see class docstring)
- Return type:
- property query_params: QueryParams
Query string parameters as QueryParams object.
- property scope: MutableMapping[str, Any]
Raw ASGI scope dict.
- property state: State
Request-scoped state container.
- property url: URL
Full request URL.
- Parsing flow (in
- class genro_asgi.request.MsgRequest[source]
Bases:
BaseRequestMessage-based request adapter (WSX over WebSocket, NATS, etc.).
Parses WSX:// formatted messages into BaseRequest interface. Transport-agnostic: works with any message-based protocol.
- property client: tuple[str, int] | None
Client address as raw (host, port) tuple from WebSocket scope.
Unlike HttpRequest.client (which wraps in Address), WSX messages return the raw tuple because WebSocket connections are long-lived and the overhead of wrapping each message is unnecessary.
- async init(scope, receive, send=None, **kwargs)[source]
Async initialization - parses WSX message.
- Return type:
- property scope: MutableMapping[str, Any]
Access to raw ASGI scope.
- class genro_asgi.request.RequestRegistry(factories=None)[source]
Bases:
objectRegistry for creating and tracking active requests.
Responsibilities: - Creates appropriate request based on scope[“type”] using factories dict - Calls async init() on the created request - Tracks active requests for monitoring and metrics - Provides iteration and lookup by request ID
Example
registry = RequestRegistry() request = await registry.create(scope, receive, send) print(f”Active: {len(registry)}”) registry.unregister()
- async create(scope, receive, send=None, **kwargs)[source]
Create and register a request from ASGI scope.
- Return type:
- property current: BaseRequest | None
Current request from ContextVar.
- factories