Opens one connection per request by default; opt into keep-alive
reuse for cleartext HTTP/1.1 with :meth:with_pool and into HTTP/3
QUIC connection reuse (on by default once h3 is used). Follows
redirects per a configurable :meth:with_redirect_policy, optionally
auto-decompresses responses, retries transient failures via
:meth:with_retry, and keeps a session cookie jar via
:meth:with_cookies.
This type is Movable but not Copyable. It supports the context
manager protocol (__enter__) for use with with.
Constructors follow a natural ergonomic order:
HttpClient() — defaults only
HttpClient("https://api.example.com") — base URL positional
HttpClient(BearerAuth("token")) — auth first
HttpClient("https://api.example.com", BearerAuth("token")) — base URL + auth
Example:
# Simple one-liner
var resp = HttpClient().get("https://httpbin.org/get")
# Session with base URL and auth — no repeated prefixes
with HttpClient("https://api.example.com", BearerAuth("tok")) as c:
c.post("/items", '{"name": "flare"}').raise_for_status()
var items = c.get("/items").json()
__init__
def __init__(out self, base_url: String = "", max_redirects: Int = Int(10), timeout_ms: Int = Int(30000), user_agent: String = DEFAULT_USER_AGENT, prefer_h2c: Bool = False, h2c_upgrade: Bool = False, prefer_http3: Bool = False, auto_decompress: Bool = True)
Initialise an HttpClient with secure defaults.
- Args
base_url: Optional base URL prepended to relative paths.max_redirects: Maximum number of redirects to follow (default 10).timeout_ms: Connect timeout in milliseconds (default 30 s).
Body reads stay unbounded unless
:meth:with_read_timeout sets a read timeout.user_agent: Value for the User-Agent header.prefer_h2c: When True, http:// requests speak
HTTP/2 over cleartext via prior knowledge. https://
requests always negotiate via ALPN regardless.h2c_upgrade: When True, http:// requests issue an
HTTP/1.1 Upgrade: h2c handshake (RFC 7540 §3.2)
instead of using prior knowledge; the connection switches
to HTTP/2 only if the server returns 101 Switching Protocols, otherwise it stays on HTTP/1.1.prefer_http3: When True, https:// requests prefer
HTTP/3 over QUIC on first contact rather than waiting
for an Alt-Svc advert; any QUIC dial failure falls
back transparently to h2/h1. Without this, h3 still
kicks in automatically once a server advertises it via
Alt-Svc.auto_decompress: When True (default), compressed response
bodies are decoded transparently.
def __init__(out self, tls: TlsConfig, base_url: String = "", max_redirects: Int = Int(10), timeout_ms: Int = Int(30000), user_agent: String = DEFAULT_USER_AGENT, prefer_h2c: Bool = False, h2c_upgrade: Bool = False, prefer_http3: Bool = False, auto_decompress: Bool = True)
Initialise an HttpClient with custom TLS configuration.
def __init__[A: Auth](out self, auth: A, base_url: String = "", max_redirects: Int = Int(10), timeout_ms: Int = Int(30000), user_agent: String = DEFAULT_USER_AGENT, prefer_h2c: Bool = False, h2c_upgrade: Bool = False, prefer_http3: Bool = False, auto_decompress: Bool = True)
Initialise an HttpClient with authentication.
def __init__[A: Auth](out self, base_url: String, auth: A, max_redirects: Int = Int(10), timeout_ms: Int = Int(30000), user_agent: String = DEFAULT_USER_AGENT, prefer_h2c: Bool = False, h2c_upgrade: Bool = False, prefer_http3: Bool = False, auto_decompress: Bool = True)
Initialise an HttpClient with a base URL and authentication.
send_chunked
def send_chunked[B: ChunkSource](self, method: String, url: String, mut source: B, content_type: String = "application/octet-stream", body_size: Int = Int(-1), cancel: Cancel = Cancel.never()) -> Response
Send a request whose body is streamed from a ChunkSource using Transfer-Encoding: chunked, without materializing the full body in memory.
For large uploads (multi-MB / multi-GB) this keeps client memory
bounded to one chunk in flight: the source's next(cancel) is
pulled, framed as a chunked-transfer chunk, and written straight
to the socket. The body is never assembled into a single buffer.
This is an explicit bounded-memory path over HTTP/1.1 (cleartext
or TLS, ALPN forced to http/1.1); it deliberately does not
go through connection pooling, redirects, retries, h2, or h3
(all of which buffer or re-send the body). Use :meth:post /
:meth:send for those.
- Args
method: HTTP method (e.g. "POST" / "PUT").url: Target URL (absolute or relative to base_url).source: A ChunkSource yielding body chunks; pulled to
exhaustion (next returns None).content_type: Content-Type header value. Defaults to
application/octet-stream.body_size: Total body length in bytes when known (sent as
Content-Length); negative selects chunked framing.cancel: Cancellation token checked while the body is pulled.
Raises NetworkError: On connection or I/O failure.
post_streaming
def post_streaming(self, url: String, body: String) -> HttpStreamResponse
POST a JSON body and stream the response.
The shape server-sent events and JSON-lines APIs want: a small
request, then a response read incrementally for as long as the
server keeps writing.
- Args
url: Absolute URL, or a path when the client has a base URL.body: Request body, sent as application/json.
Raises NetworkError: On a connect, TLS or read failure.
post
def post(self, url: String, body: String) -> Response
Perform a POST request with a JSON string body.
Sets Content-Type: application/json automatically. This is the
default for string bodies because virtually every HTTP API that accepts
a string payload expects JSON.
Example:
var resp = client.post("https://httpbin.org/post", '{"key": "value"}')
resp.raise_for_status()
- Args
url: The target URL (absolute or relative to base_url).body: The JSON request body as a String.
Raises NetworkError: On connection or I/O failure.
TooManyRedirects: If the redirect limit is exceeded.
def post(self, url: String, body: Value) -> Response
Perform a POST request with a json.Value body.
Serialises body to JSON with dumps and sets
Content-Type: application/json automatically.
- Args
url: The target URL (absolute or relative to base_url).body: A json.Value to serialise and send.
Raises NetworkError: On connection or I/O failure.
TooManyRedirects: If the redirect limit is exceeded.
def post(self, url: String, body: List[UInt8]) -> Response
Perform a POST request with a raw byte body.
No Content-Type header is set automatically; the caller is
responsible for setting it via a custom Request if required.
- Args
url: The target URL (absolute or relative to base_url).body: The raw request body bytes.
Raises NetworkError: On connection or I/O failure.
TooManyRedirects: If the redirect limit is exceeded.
put
def put(self, url: String, body: String) -> Response
Perform a PUT request with a JSON string body.
Sets Content-Type: application/json automatically.
- Args
url: The target URL (absolute or relative to base_url).body: The JSON request body as a String.
Raises NetworkError: On connection or I/O failure.
TooManyRedirects: If the redirect limit is exceeded.
def put(self, url: String, body: Value) -> Response
Perform a PUT request with a json.Value body.
Serialises body to JSON with dumps and sets
Content-Type: application/json automatically.
- Args
url: The target URL (absolute or relative to base_url).body: A json.Value to serialise and send.
Raises NetworkError: On connection or I/O failure.
TooManyRedirects: If the redirect limit is exceeded.
def put(self, url: String, body: List[UInt8]) -> Response
Perform a PUT request with a raw byte body.
No Content-Type header is set automatically.
- Args
url: The target URL (absolute or relative to base_url).body: The raw request body bytes.
Raises NetworkError: On connection or I/O failure.
TooManyRedirects: If the redirect limit is exceeded.
patch
def patch(self, url: String, body: String) -> Response
Perform a PATCH request with a JSON string body.
Sets Content-Type: application/json automatically.
- Args
url: The target URL (absolute or relative to base_url).body: The JSON request body as a String.
Raises NetworkError: On connection or I/O failure.
TooManyRedirects: If the redirect limit is exceeded.
def patch(self, url: String, body: Value) -> Response
Perform a PATCH request with a json.Value body.
Serialises body to JSON with dumps and sets
Content-Type: application/json automatically.
- Args
url: The target URL (absolute or relative to base_url).body: A json.Value to serialise and send.
Raises NetworkError: On connection or I/O failure.
TooManyRedirects: If the redirect limit is exceeded.
def patch(self, url: String, body: List[UInt8]) -> Response
Perform a PATCH request with a raw byte body.
No Content-Type header is set automatically.
- Args
url: The target URL (absolute or relative to base_url).body: The raw request body bytes.
Raises NetworkError: On connection or I/O failure.
TooManyRedirects: If the redirect limit is exceeded.