Request and context

This page documents the per-request Context (c) and inbound Request (c.req). Registration, mount, middleware, path/host matching, and what goes into c.route are on Routing. Outbound bytes, Writer, and cookies are on Responses.

Context

Context is the per-request bag the framework constructs before your handler runs. You do not instantiate it yourself.

AttributePurpose
appThe App instance handling this request. Use for app.url_for, app.create_task, sharing references mounted during bootstrap.
reqRequest: method, path, headers, lazy query/cookies, body readers.
spanRequest telemetry span (started/ended around App.__call__). Use c.span.attr, event, fail for dimensions and errors.
stateMutable dict[str, Any]. Middleware can stash values; inner layers and the handler read them. Prefer small, well-known keys.
routeRouteMatch: canonical pattern string and captured segments. Read values from c.route.params (Route parameters). Empty pattern on 404 / some 405 paths—check before using params. Filled when the app resolves the route, immediately before your handler runs.

Send the response with w (Writer); read the inbound message from c.req (Request).

Request

Stable view of the request line and headers. The protocol builds it; handlers only read. Reach everything through c.req.

Request fields and accessors

MemberHow you access itNotes
HTTP methodc.req.methodstr (e.g. "GET"). Fixed when the request starts.
Pathc.req.pathPath only; no query string. Fixed at start.
Headersc.req.headersHeaders — case-insensitive keys; get, getlist, items, etc.
Protocolc.req.protocol_versionstr, e.g. "1.1".
Keep-alivec.req.keep_alivebool.
Hostc.req.hostHost header without port, lowercased; IPv6 keeps [...]. Lazy on first read. "" if missing.
Query stringc.req.queryQueryParams. Lazy. Parsed from the URL’s ?… portion. Use as_dict() / as_lists() when validating the whole query (e.g. Pydantic).
Raw query bytesc.req.query_bytesSame string as in the URL after ?, without the ? (empty bytes if none). Use when you parse or validate the query yourself.
Cookiesc.req.cookiesdict[str, str] merged from Cookie headers. Lazy.
Body (buffered)await c.req.body()Full body as bytes. Uses the internal reader (size cap, timeouts). Once buffered, later await c.req.body() calls return the same bytes.
Body (stream)async for chunk in c.req.stream():Chunked iterator; same limits and errors as body(). If the body was already fully buffered, stream() yields that single cached chunk once.

On body() and stream():

  • HttpException(413) if the body exceeds the configured maximum size (default 10 MiB).

  • HttpException(408) if idle between chunks exceeds the body read timeout (slow upload / slowloris guard; default 30 seconds between chunks unless configured otherwise).

  • ClientDisconnected if the peer closes before the body completes.

Start with either streaming or a full read: if stream() has already started iterating and the body is not yet cached, a second stream() or a conflicting read raises RuntimeError (single in-flight consumer). After the body is fully buffered, body() and stream() can both use the cached bytes without error.

Cookie response headers use stario.cookies with w (Cookies).

class Request(*, method='GET', path='/', query_bytes=b'', protocol_version='1.1', keep_alive=True, headers, body)

Stable snapshot of request-line data plus headers; body I/O goes through an internal BodyReader.

query_bytes is the raw ?-suffix from the URL (no leading ?). host, query, and cookies are computed lazily on first access. Do not reassign query_bytes after construction—it would desynchronize the cached query view.

async Request.body()

Return the entire body as bytes (empty if there is no body reader).

Raises

HttpException: 413 when the body exceeds the configured maximum size. HttpException: 408 when bytes stall longer than the body read timeout (slow upload / slowloris guard). ClientDisconnected: When the peer closes before the body finishes. RuntimeError: If the body was already streamed via stream().

Internally uses BodyReader.read on the protocol-owned reader (size cap, timeouts, backpressure).

async Request.stream()

Stream the body; mutually exclusive with body() for a given request.

Raises

HttpException: 413 / 408 for oversize or stalled uploads (same rules as body()). ClientDisconnected: When the peer closes before the body finishes. RuntimeError: If stream() or body() already consumed this body.

Yields

Consecutive body chunks.

Internally uses BodyReader.stream.

class QueryParams(raw)

View over a parsed query string preserving repeated keys.

QueryParams.as_dict(*, last=True)

One string per key, suitable for Pydantic model_validate and similar.

Repeated keys (?a=1&a=2) keep the first or last value; most UIs send at most one value per key. For every value as a list, use as_lists.

QueryParams.as_lists()

All keys with every repeated value preserved (copy of each list).

Use with schemas whose fields are list[str] (or similar) for ?tag=a&tag=b-style parameters.

QueryParams.get(key, default=None)

First value for key, or default when the key is absent.

QueryParams.getlist(key)

Every value for key (empty list if missing), preserving duplicates from the query string.

QueryParams.items()

All key-value pairs, flattened.

class Headers(raw_header_data=None)

HTTP header map: validated str/bytes API plus r* helpers for already-normalized wire bytes.

Headers.add(name, value)

Append a value, allowing duplicates (e.g. multiple Set-Cookie).

Parameters

  • nameHeader name (canonical names are validated against known tokens when using str).
  • valueHeader value; encoded for wire form.

Returns

self for chaining.

Headers.clear()

Remove all headers.

Headers.get(name, default=None)

First header value as str (Latin-1 decoded), or default.

Headers.getlist(name)

Every value for a possibly multi-valued header, as strings.

Headers.items()

Return all header name-value pairs (flattened).

Headers.radd(name, value)

Like add but assumes name is already lowercased header-name bytes (no validation).

Headers.remove(name)

Remove a header.

Headers.rget(name, default=None)

First value as wire bytes (name must be lowercased header bytes).

Headers.rgetlist(name)

All values as wire bytes (for duplicated headers such as Set-Cookie).

Headers.rset(name, value)

Like set for pre-lowercased name bytes (response helpers use this in hot paths).

Headers.set(name, value)

Replace any existing values for this header name.

Parameters

  • nameHeader name.
  • valueNew value.

Returns

self for chaining.

Headers.setdefault(name, value)

Set header if not present, return value as string.

Headers.update(other)

class RouteMatch(pattern, params)

Result of routing: a canonical pattern string plus captured path/host segments.

Fields

  • pattern(str):Matched route template (useful for logs), including host part when present.
  • params(Mapping):Map from {param} / {rest...} names to decoded segment text.