nimble-http
Async HTTP client for service-to-service calls: fully typed, timeouts on every request, bounded retries for transient failures only, and typed errors that tell a caller whether retrying is worth it.
Built on httpx. One AsyncHttpClient owns one connection pool — build it once
per process (or per Lambda container) and share it.
Install
pip install nimble-http
Usage
from nimble_http import AsyncHttpClient, HttpMethod, HttpRequest, RetryPolicy
async def send() -> None:
async with AsyncHttpClient(
base_url="https://graph.facebook.com",
headers={"authorization": "Bearer <token>"},
read_timeout_seconds=10.0,
retry=RetryPolicy(max_attempts=3),
) as client:
response = await client.send(
HttpRequest(
method=HttpMethod.POST,
url="/v26.0/<phone_number_id>/messages",
json={"messaging_product": "whatsapp", "to": "<phone>"},
),
)
print(response.json())
Typed responses
from pydantic import BaseModel
class SendResult(BaseModel):
messaging_product: str
result = await client.send_model(request, SendResult)
Concurrency
responses = await client.send_all(requests, max_concurrency=5)
send_all uses an asyncio.TaskGroup: the first failure cancels the rest and
surfaces as an ExceptionGroup. Catch it with except*.
Streaming
async for chunk in client.stream(request):
...
body = await client.send_bytes(request)
Streaming is never retried once the response starts arriving.
Errors
Every failure is an HttpError. Check error.is_transient to decide whether to
let a worker retry or to fail definitively.
| Error | Raised when | is_transient |
|---|---|---|
HttpTimeoutError |
connect/read/write timeout | True |
HttpTransportError |
DNS, TLS, connection, protocol failure | True |
HttpStatusError |
status outside 2xx (carries status_code, headers, content) |
only for 408, 425, 429, 5xx |
HttpDecodeError |
body is not valid JSON / does not match the model | False |
Retries
RetryPolicy retries timeouts, transport errors and the status codes in
retryable_status_codes (408, 425, 429, 500, 502, 503, 504 by default), with
exponential backoff plus jitter. A Retry-After response header wins over the
computed backoff, capped by backoff_max_seconds. Use NO_RETRY to disable.
Testing
Pass an httpx.AsyncBaseTransport to drive the client against a stub — no
network, no monkeypatching:
import httpx
client = AsyncHttpClient(
base_url="https://api.example.test",
transport=httpx.MockTransport(lambda request: httpx.Response(200, json={})),
)
Breaking change in 0.2.0
The Requests, Session and Singleton classes are gone. They were untyped,
shared a process-wide mutable session, had a fixed 600s timeout with no
per-request override, and Requests.multiple recursed into itself. Migration:
| 0.1.0 | 0.2.0 |
|---|---|
Requests(raise_for_status=True) |
AsyncHttpClient(raise_for_status=True) |
await r.single(payload) |
await client.send_json(HttpRequest(...)) |
await r.single_raw(payload) |
await client.send(HttpRequest(...)) |
await r.multiple(payloads) |
await client.send_all([HttpRequest(...), ...]) |
await r.single_bin(payload) |
await client.send_bytes(HttpRequest(...)) |
Metadata
Release files for nimble-http 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| nimble_http-0.2.0.tar.gz | 6.6 kB | Without provenance | Details for nimble_http-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| nimble_http-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for nimble_http-0.2.0-py3-none-any.whl |
Total release size: 15.9 kB
Release files / nimble_http-0.2.0.tar.gz
| Download URL | nimble_http-0.2.0.tar.gz |
|---|---|
| Size | 6.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3c372376008b4bda1b53913d14bd45f2112cbdfc76b8d971acba6167b00553b3
|
|
BLAKE2b-256 checksum How to use checksums |
2873edf3c07d36f2332f2ec5d5d91d99af71f92e11e23d4885435e3189c42935
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.5.1 CPython/3.12.3 Linux/7.0.0-1017-azure
|
Release files / nimble_http-0.2.0-py3-none-any.whl
| Download URL | nimble_http-0.2.0-py3-none-any.whl |
|---|---|
| Size | 9.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ee41cfbe53a30d63bc011848c02df440b6b700b55a905ebb2e9be1c44d5429b1
|
|
BLAKE2b-256 checksum How to use checksums |
a05f4c1d03aa298f629f363f34369e291c6b666d1e1029ab10c4e44d8e7d0660
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.5.1 CPython/3.12.3 Linux/7.0.0-1017-azure
|
Security for nimble-http 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.