Skip to main content

nodus-http

Outbound HTTP client with circuit breaker, retry, and OTel trace propagation.

Wraps httpx with optional circuit-breaker protection, configurable retry logic, and trace ID header injection. All integrations are constructor-injected — no globals or module-level configuration.

Status: v0.1.0 — prepared, not yet published.


Install

pip install nodus-http

# With circuit breaker:
pip install "nodus-http[circuit-breaker]"

# With OTel trace propagation:
pip install "nodus-http[otel]"

What it provides

Component Purpose
HttpClient httpx wrapper with circuit breaker, retry, and trace headers
HttpResponse Normalised response: status_code, headers, body, json(), ok
RetryConfig Retry settings: max attempts, retryable status codes, backoff
inject_trace_headers Add X-Trace-ID to a headers dict via callback

Quick start

from nodus_http import HttpClient

client = HttpClient(base_url="https://api.example.com", timeout=10.0)
response = client.get("/users/123")

if response.ok:
    data = response.json()

HttpClient

from nodus_http import HttpClient, RetryConfig
from nodus_circuit_breaker import CircuitBreaker

client = HttpClient(
    base_url="https://api.example.com",
    timeout=10.0,
    default_headers={"Authorization": "Bearer my-token"},
    retry_config=RetryConfig(
        max_attempts=3,
        retryable_status_codes={429, 502, 503, 504},
        backoff_ms=200,
        exponential=True,
    ),
    circuit_breaker=CircuitBreaker("api.example.com", failure_threshold=5),
    get_trace_id_fn=lambda: my_context.trace_id,  # optional
)

# Sync
response = client.get("/path")
response = client.post("/path", json={"key": "value"})
response = client.put("/path", json={...})
response = client.delete("/path")
response = client.request("PATCH", "/path", json={...})

# Async
response = await client.get_async("/path")
response = await client.post_async("/path", json={...})

HttpResponse

response.ok           # True if 2xx
response.status_code  # int
response.headers      # dict
response.body         # bytes
response.json()       # parsed JSON (dict | list | ...)
response.text         # decoded string

RetryConfig

from nodus_http import RetryConfig

config = RetryConfig(
    max_attempts=3,
    retryable_status_codes={429, 502, 503, 504},
    backoff_ms=100,
    exponential=True,   # doubles each attempt: 100ms, 200ms, 400ms
)

Retries fire on network errors and on responses with a retryable status code. Non-retryable errors (4xx except those in retryable_status_codes) are not retried.


Trace header injection

from nodus_http import inject_trace_headers

headers = {"Content-Type": "application/json"}
headers = inject_trace_headers(headers, get_trace_id_fn=lambda: "trace-abc")
# headers now includes "X-Trace-ID": "trace-abc"

Pass get_trace_id_fn to HttpClient to inject the trace ID automatically on every request.


Circuit breaker

Pass any object with a .call(fn) method as circuit_breaker. The nodus-circuit-breaker package provides a compatible CircuitBreaker:

pip install "nodus-http[circuit-breaker]"
from nodus_circuit_breaker import CircuitBreaker

cb = CircuitBreaker("my-api", failure_threshold=3, recovery_timeout_secs=30)
client = HttpClient("https://api.example.com", circuit_breaker=cb)

When the circuit is open, client.get(...) raises CircuitOpenError.


Design

  • httpx required. All other integrations (circuit breaker, retry, trace) are injected and optional.
  • No globals. All configuration is per-HttpClient instance.
  • Normalised response. HttpResponse wraps httpx responses with a consistent interface regardless of sync/async path.

Development

pip install -e ".[dev]"
pytest tests/ -q

Tests use respx for request mocking.


License

MIT — see LICENSE.

Metadata

Release files for nodus-http 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nodus-http 0.1.0
File Size Uploaded
nodus_http-0.1.0.tar.gz 8.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nodus-http 0.1.0
File Interpreter ABI Platform
nodus_http-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 16.0 kB

Release files / nodus_http-0.1.0.tar.gz

Download URL nodus_http-0.1.0.tar.gz
Size 8.5 kB
Tags Source
SHA-256 checksum
How to use checksums
a532c6477f2e3e6d405aaf2894cf822a40630fa61d407fb3ab28cbb0816fc587
BLAKE2b-256 checksum
How to use checksums
e3fd979f44207c6d22770412f25b4f3ed34cc00e2706c5feebdb49f8b57b48b9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.9

Release files / nodus_http-0.1.0-py3-none-any.whl

Download URL nodus_http-0.1.0-py3-none-any.whl
Size 7.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8d22c34681c03be6dc1142a178f669766690b4a918b7c03ea152be74700e8033
BLAKE2b-256 checksum
How to use checksums
499d03d5b35afcf86b1e9c3689a7b0cb8184175755e5e40dcbfd318f1fc66a39
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.9

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page