Skip to main content

Resilience-first async HTTP client framework for Python

Project description

httpware

Test PyPI version Python versions License: MIT

Async HTTP client framework for Python.

httpware is a thin opinionated wrapper around httpx2. It re-exports httpx2.Request/httpx2.Response, adds a middleware chain composed at client construction, supports opt-in typed response decoding (pydantic and msgspec are both extras), and raises a status-keyed exception tree automatically on 4xx/5xx. It also ships a small resilience suite — Retry middleware with a Finagle-style RetryBudget, plus a Bulkhead concurrency limiter — under httpware.middleware.resilience.

Status: Pre-1.0. Public API is subject to change between minor releases until v1.0.

Install

pip install httpware                # core only — no decoder
pip install httpware[pydantic]      # + PydanticDecoder (the default-decoder path)
pip install httpware[msgspec]       # + MsgspecDecoder
pip install httpware[all]           # everything declared above (pydantic, msgspec, otel)

AsyncClient() with no decoder= argument defaults to constructing a PydanticDecoder; that path requires the pydantic extra and raises ImportError at AsyncClient.__init__ if it is missing.

Quickstart

Requires: pip install httpware[pydantic]

from httpware import AsyncClient
from pydantic import BaseModel


class User(BaseModel):
    id: int
    name: str


async def main() -> None:
    async with AsyncClient(base_url="https://api.example.com") as client:
        user = await client.get("/users/1", response_model=User)
        print(user.name)

With resilience middleware

Compose resilience middleware at construction; Bulkhead goes outside Retry so one slot covers all retry attempts.

from httpware import AsyncClient, Bulkhead, Retry


async def main() -> None:
    async with AsyncClient(
        base_url="https://api.example.com",
        middleware=[
            Bulkhead(max_concurrent=10),  # cap total in-flight
            Retry(),                       # default: 3 attempts, full-jitter backoff
        ],
    ) as client:
        user = await client.get("/users/1", response_model=User)

Streaming responses

For large responses or server-sent events, stream the body chunk-by-chunk. stream() is an async context manager:

from httpware import AsyncClient


async def main() -> None:
    async with AsyncClient(base_url="https://api.example.com") as client:
        async with client.stream("GET", "/big-file") as response:
            async for chunk in response.aiter_bytes():
                process(chunk)

stream() auto-raises StatusError subclasses on 4xx/5xx with the response body pre-read, so exc.response.content is accessible from the caught exception.

It does NOT pass through the middleware chain: Retry, Bulkhead, and any custom middleware are bypassed. (Retry separately refuses to retry any request — stream or non-stream — whose body was an async-iterable, since streams can't replay across attempts.)

Errors

All 4xx/5xx responses raise typed exceptions automatically: NotFoundError, ServiceUnavailableError, RateLimitedError, etc. — all subclasses of httpware.StatusError. Transport-layer transient failures raise NetworkError; the resilience middleware raise RetryBudgetExhaustedError and BulkheadFullError. Everything inherits httpware.ClientError.

Observability

Retry and Bulkhead emit operational events via two channels — stdlib logging records (always on) and OpenTelemetry span events (when opentelemetry-api is installed).

Logger names (httpware.retry, httpware.bulkhead) and event names (retry.giving_up, retry.budget_refused, retry.streaming_refused, bulkhead.rejected) are the stable public contract.

import logging

# Enable visibility into retry / bulkhead operational events
logging.getLogger("httpware.retry").setLevel(logging.WARNING)
logging.getLogger("httpware.bulkhead").setLevel(logging.WARNING)

For OTel attribute enrichment on the active span — install the extra:

pip install httpware[otel]

When installed, _emit_event calls trace.get_current_span().add_event(name, attributes=...) automatically. We never create our own spans; for HTTP-level tracing install opentelemetry-instrumentation-httpx separately.

🗒️ Release notes

📦 PyPI

📝 License

Part of modern-python

Browse the full list of templates and libraries in modern-python — see the org profile for the categorized index.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

httpware-0.6.0.tar.gz (16.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

httpware-0.6.0-py3-none-any.whl (22.2 kB view details)

Uploaded Python 3

File details

Details for the file httpware-0.6.0.tar.gz.

File metadata

  • Download URL: httpware-0.6.0.tar.gz
  • Upload date:
  • Size: 16.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for httpware-0.6.0.tar.gz
Algorithm Hash digest
SHA256 466c18f8b2cb0905e7f94a51425a88a0f717d349dd3e6722e746af38fb2337c5
MD5 7a10dbd3b9291f441ebcb7c91637cabf
BLAKE2b-256 ddc358382a4a17f3d4b00c726c3818e275f65f50f7a5fe88efaef92d62d6d103

See more details on using hashes here.

File details

Details for the file httpware-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: httpware-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 22.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for httpware-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a57e7b0499f07d1ad02906a2abdf2574391da41cdebee0a7de508112ce181b1f
MD5 eee62f71edb5066984e3b95dbb907745
BLAKE2b-256 52d31fec9f916445793a7a070a80cef7089fdf5be9e4509d0622b5241054f2af

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page