Skip to main content

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

Project description

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.

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

nodus_http-0.1.0.tar.gz (8.5 kB view details)

Uploaded Source

Built Distribution

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

nodus_http-0.1.0-py3-none-any.whl (7.5 kB view details)

Uploaded Python 3

File details

Details for the file nodus_http-0.1.0.tar.gz.

File metadata

  • Download URL: nodus_http-0.1.0.tar.gz
  • Upload date:
  • Size: 8.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for nodus_http-0.1.0.tar.gz
Algorithm Hash digest
SHA256 a532c6477f2e3e6d405aaf2894cf822a40630fa61d407fb3ab28cbb0816fc587
MD5 ff6d8ded433536406e804fffa03c2af4
BLAKE2b-256 e3fd979f44207c6d22770412f25b4f3ed34cc00e2706c5feebdb49f8b57b48b9

See more details on using hashes here.

File details

Details for the file nodus_http-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: nodus_http-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 7.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for nodus_http-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8d22c34681c03be6dc1142a178f669766690b4a918b7c03ea152be74700e8033
MD5 e930badc2000c17df3c590a64b226989
BLAKE2b-256 499d03d5b35afcf86b1e9c3689a7b0cb8184175755e5e40dcbfd318f1fc66a39

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