http.request
import http.request
httplifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelledhttp.request.*needsimport http.request.
HttpRequest: one inbound request, with its method, target, headers and
body, plus the query string and route parameters already parsed.
The query-string functions are separate because they are useful on their
own: build_query_string() is what constructs a URL to request, not
only what reads one.
Functions
parse_query_string()
http.parse_query_string(text) -> dict
Decodes an application/x-www-form-urlencoded string - a query string,
or a form body - into name -> [value, ...].
+ decodes to a space and %xx to the byte it names, both of which
apply to names as well as values. A parameter with no = maps to an
empty string rather than to nil, matching what every server-side form
API does with ?debug.
Parameters
text(?string)
Returns dict
build_query_string()
http.build_query_string(parameters: dict) -> string
Encodes parameters as an application/x-www-form-urlencoded string.
Values may be lists, in which case the name repeats.
Parameters
parameters(dict)
Returns string
Classes
HttpRequest
class http.HttpRequest
An HTTP request, in both directions.
On the server side an instance arrives fully parsed: method, path,
query, headers, cookies and body are all populated, with
form(), json_body() and files() decoding the body on first use
according to its Content-Type.
On the client side, HttpClient builds one of these for every request
it sends, so anything you can inspect on the server you can also set
before sending.
- printable — has a
@to_string(), soechoandprint()show something useful - serializable — has a
@to_json(), so it can be handed straight tojson.encode()
Fields
| Field | Type | Description |
|---|---|---|
method | string | The request method, uppercased: 'GET', 'POST', and so on. |
target | string | The request target exactly as it appeared on the request line, before any decoding - '/search?q=a%20b'. |
path | string | The path, percent-decoded and with its . and .. segments resolved. |
query_string | string | The query string, without the leading ?, or ''. |
query | dict | The decoded query parameters, as name -> [value, ...]. |
version | string | The protocol version: '1.0', '1.1', '2' or '3'. |
headers | Headers | The request header fields. |
cookies | dict | The cookies the client sent, as name -> value. |
params | dict | Path parameters captured by the route that matched, e.g. id for a route registered as /users/:id. |
body | bytes | The request body. |
remote_address | ?string | The address of the peer at the other end of the socket. |
secure | bool | Whether the request arrived over TLS. |
scheme | string | The scheme the request was made with: 'http' or 'https'. |
authority | ?string | The authority the request was addressed to, from HTTP/2’s :authority or HTTP/1.1’s Host header, port… |
context | dict | Free-form storage for whatever middleware wants to attach to a request - a resolved user, a request id, a… |
body_reader | ?BodyReader | The reader for the body, when the route asked to stream it rather than have it materialised. |
Constructor
http.HttpRequest(method, target, headers)
Parameters
method(?string)target(?string)headers(?Headers)
HttpRequest.set_target()
http.HttpRequest.set_target(target: string)
Sets the request target and re-derives path, query_string and
query from it.
The path is percent-decoded and then normalised, in that order. Doing it
the other way round is the classic traversal hole: %2e%2e%2f looks
like an ordinary segment until it is decoded.
Parameters
target(string)
HttpRequest.header()
http.HttpRequest.header(name: string, fallback) -> any
A request header value, or fallback when absent.
Parameters
name(string)fallback(?any)
Returns any
HttpRequest.query_param()
http.HttpRequest.query_param(name: string, fallback) -> any
The first value of the query parameter name, or fallback.
Parameters
name(string)fallback(?any)
Returns any
HttpRequest.param()
http.HttpRequest.param(name: string, fallback) -> any
A path parameter captured by the matched route, or fallback.
Parameters
name(string)fallback(?any)
Returns any
HttpRequest.cookie()
http.HttpRequest.cookie(name: string, fallback) -> any
A cookie value, or fallback.
Parameters
name(string)fallback(?any)
Returns any
HttpRequest.session()
http.HttpRequest.session() -> Session
This request’s session.
The session is put here by http.session.session(), so a server that
never registered that middleware has none, and asking for one says so
rather than handing back nil for a handler to misread as an empty
session.
request.session().set('account', account.id)
Returns Session
Raises SessionError if the session middleware is not registered
HttpRequest.content_type()
http.HttpRequest.content_type() -> ?string
The media type of the body, without parameters, or nil.
Returns ?string
HttpRequest.content_length()
http.HttpRequest.content_length() -> number
The declared body length, or -1 when the request carries no
Content-Length (which for a chunked body it will not).
Returns number
HttpRequest.text()
http.HttpRequest.text() -> string
The body decoded as UTF-8 text.
Returns string
HttpRequest.json_body()
http.HttpRequest.json_body() -> any
The body parsed as JSON.
Parses once and caches, so calling this in both a middleware and a handler costs one parse.
Returns any
Raises HttpError if the body is not valid JSON
HttpRequest.form()
http.HttpRequest.form() -> dict
The submitted form fields, as name -> value, from either an
application/x-www-form-urlencoded or a multipart/form-data body. A
body of neither type gives an empty dictionary rather than raising.
Repeated names keep their first value here; use form_all() when a
field can legitimately repeat.
Returns dict
HttpRequest.form_all()
http.HttpRequest.form_all() -> dict
The submitted form fields as name -> [value, ...], keeping every value
of a repeated name.
Returns dict
HttpRequest.form_field()
http.HttpRequest.form_field(name: string, fallback) -> any
A single form field’s first value, or fallback.
Parameters
name(string)fallback(?any)
Returns any
HttpRequest.files()
http.HttpRequest.files() -> dict
The files uploaded in a multipart/form-data body, as name -> [UploadedFile, ...].
Empty for any other body type.
Returns dict
HttpRequest.file()
http.HttpRequest.file(name: string) -> ?UploadedFile
The first file uploaded under name, or nil.
Parameters
name(string)
Returns ?UploadedFile
HttpRequest.input()
http.HttpRequest.input(source: ?string) -> dict
The request’s input as one dictionary, ready to hand to a validator.
With no argument, three sources are merged, each overriding the one before it:
- route parameters, from the pattern that matched 2. query string parameters 3. the body - a JSON object’s keys, or the submitted form fields
Pass source to take exactly one of them instead: 'params', 'query'
or 'body'.
A query or form field is a list on the wire, since a name may legally
repeat. A name carrying exactly one value is flattened to that value
here, so a rule expecting a string sees a string; a name carrying
several stays a list. A field that must always be a list, however many
values arrived, is better read through form_all() or query directly.
Uploaded files are not included - nothing a schema can say about a file
is expressible as a rule over its bytes. Reach them with file() and
check them by hand.
A JSON body that is not an object (an array, a bare string) contributes
nothing, since there are no names to merge; read it with json_body()
instead.
Parameters
source(?string) —'params','query','body', or'all'(the default)
Returns dict
Raises ValueError if source names something else
HttpRequest.validate()
http.HttpRequest.validate(schema, source: ?string)
Validates the request’s input against schema and returns the data that
was validated.
schema is anything with a check_or_raise() method - a
validate.Schema in practice:
import validate
var create_user = validate.schema({
name: validate.required().string().max_length(100),
email: validate.required().string().email(),
})
server.post('/users', @(request, response) {
var data = request.validate(create_user)
response.json(create_account(data), 201)
})
Failure raises the schema’s own error - validate.ValidationError
- carrying an
errorslist of{ field, message }. Catch it to turn it into whatever your API answers with:
catch {
var data = request.validate(create_user)
response.json(create_account(data), 201)
} as error {
response.json({ errors: create_user.group_errors(error.errors) }, 422)
}
Parameters
schema(Schema)source(?string) — asinput(); defaults to'all'
Returns — dict: the input that was validated
Raises ValidationError when the input does not satisfy the schema
Raises TypeError if schema is not an object that can validate
Note: This deliberately does not import the
validatemodule. Any object exposingcheck_or_raise(data)works, and a server that never validates anything never pays to load it.
HttpRequest.host()
http.HttpRequest.host() -> ?string
The host the request was addressed to, without any port.
Returns ?string
HttpRequest.port()
http.HttpRequest.port() -> number
The port the request was addressed to, from the authority, or the scheme’s default when the authority named none.
Returns number
HttpRequest.url()
http.HttpRequest.url() -> string
The full absolute URL this request names.
Returns string
HttpRequest.client_ip()
http.HttpRequest.client_ip(trust_proxy: ?bool, trusted: ?list) -> ?string
The originating client’s IP address.
Directly served, that is simply the peer’s address. Behind a reverse
proxy the peer is the proxy, and the real client is in X-Forwarded-For
or RFC 7239’s Forwarded - but those are request headers, which is to
say anyone can write anything in them.
So they are only consulted when trust_proxy says to, and the value
taken is the rightmost entry that is not itself one of trusted,
walking in from the proxy end. Taking the leftmost entry - the common
shortcut - hands an attacker whatever client IP they care to claim,
which matters the moment an IP is used for rate limiting, allowlisting
or audit.
Parameters
trust_proxy(?bool) — whether to consult forwarding headers at all; defaults tofalsetrusted(?list) — proxy addresses to skip over when walking the chain
Returns ?string
HttpRequest.accepts()
http.HttpRequest.accepts(type: string) -> bool
Whether the client would accept a response of media type type, per its
Accept header. A request with no Accept accepts anything.
Parameters
type(string)
Returns bool
HttpRequest.wants_json()
http.HttpRequest.wants_json() -> bool
Whether the client would rather have JSON than HTML - the usual way to decide whether an error should be rendered as a page or returned as an object.
Returns bool
HttpRequest.bearer_token()
http.HttpRequest.bearer_token() -> ?string
The token from an Authorization: Bearer ... header, or nil when
there is no such header or it carries a different scheme.
Returns ?string
HttpRequest.is_ajax()
http.HttpRequest.is_ajax() -> bool
Whether the request was made by client-side script, as reported by the
X-Requested-With header that the major JavaScript libraries set.
Returns bool
HttpRequest.is_upgrade()
http.HttpRequest.is_upgrade(protocol: ?string) -> bool
Whether the request asks to switch to another protocol - a WebSocket handshake, or an HTTP/2 upgrade.
Parameters
protocol(?string) — check for one specific protocol
Returns bool
HttpRequest.expects_continue()
http.HttpRequest.expects_continue() -> bool
Whether the client asked the server to acknowledge before it sends the
body (Expect: 100-continue).
Returns bool
HttpRequest.is_safe()
http.HttpRequest.is_safe() -> bool
Whether this method is defined to be safe: read-only, with no side effects the client is responsible for (RFC 9110 §9.2.1).
Returns bool
HttpRequest.is_idempotent()
http.HttpRequest.is_idempotent() -> bool
Whether this method is idempotent - repeating it has the same effect as making it once (RFC 9110 §9.2.2). This is what decides whether a client may retry a request after a connection failure.
Returns bool
HttpRequest.to_wire()
http.HttpRequest.to_wire() -> string
The full request head in wire format, as it would be sent on an HTTP/1.1 connection. Useful for logging and for debugging what actually went out.
Returns string
HttpRequest.to_string()
http.HttpRequest.to_string()
HttpRequest.to_json()
http.HttpRequest.to_json()
2026, Richard Ore and Zuri contributors