Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Middleware is for *cross-cutting* concerns — behavior that should apply to eve

- **Per-call behavior that doesn't apply to other calls:** pass it through `request.extensions=` (or the `extensions=` kwarg at the call site) instead of a middleware.
- **Instance state or two-sided inspection** (a counter, a CircuitBreaker's open/closed flag, timing that needs both the request and its response, or interleaving behavior around the `await next(...)` call): write a raw `AsyncMiddleware`/`Middleware` class rather than a phase decorator — decorators are a convenience for the cases where a single function suffices.
- **Transform that doesn't need `httpware`'s exception mapping or chain ordering** (pure request/response side effects at the lowest level, including post-redirect hops): use `httpx2.event_hooks` on the wrapped `httpx2_client` instead. Phase decorators and middleware participate in the `httpware` chain (they see `httpware` exceptions and compose with `AsyncRetry`/`AsyncBulkhead`); `event_hooks` run a layer below, on every transport attempt.
- **Transform that doesn't need `httpware`'s exception mapping or chain ordering** (pure request/response side effects at the lowest level, including post-redirect hops): use `event_hooks` on an `httpx2` client you build yourself and pass as `httpx2_client=`. Phase decorators and middleware participate in the `httpware` chain (they see `httpware` exceptions and compose with `AsyncRetry`/`AsyncBulkhead`); `event_hooks` run a layer below, on every transport attempt. That is also why `httpware` refuses `event_hooks=` as a client option: an `httpx2.HTTPStatusError` raised in a hook (say, by `raise_for_status()`) reaches the chain as a plain `TransportError` instead of a `StatusError`, so `AsyncRetry` never retries it and the circuit breaker never counts it.
- **URL or header validation:** `httpx2` owns it — don't reimplement.
- **HTTP-level span creation for tracing:** install `opentelemetry-instrumentation-httpx` instead of writing an OTel middleware in httpware. `opentelemetry-instrumentation-httpx` already covers transport-level tracing, so a separate httpware layer would duplicate it. See [Observability](observability.md).
- **Redaction:** httpware redacts URLs before they reach logs, telemetry, and error messages — `user:pass@` userinfo is stripped and sensitive query- and fragment-parameter values are masked (`_internal/redaction.py`). It does **not** inspect or redact headers or request/response bodies, so if your own middleware logs those, redact them yourself (e.g. with a `logging.Filter`).
Expand Down
Loading