You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
<li><strong><ahref="../middleware/">Middleware guide</a></strong> — the <code>@async_on_error</code> decorator can translate exceptions into responses.</li>
1096
-
<li><strong><code>architecture/errors.md</code></strong> — the formal exception contract.</li>
1096
+
<li><strong><ahref="https://github.com/modern-python/httpware/blob/main/architecture/errors.md"><code>architecture/errors.md</code></a></strong> — the formal exception contract.</li>
<p>A Python HTTP client framework with sync and async clients for building resilient service clients. <code>httpware</code> is a thin opinionated wrapper around <code>httpx2</code> — it re-exports <code>httpx2.Request</code>/<code>httpx2.Response</code> as the public request/response surface, adds a middleware chain (with a built-in resilience suite: <code>AsyncRetry</code>/<code>Retry</code> + <code>RetryBudget</code>, <code>AsyncBulkhead</code>/<code>Bulkhead</code>), opt-in typed response decoding, and a status-keyed exception tree raised automatically on 4xx/5xx.</p>
<li><strong>Typed errors, no <code>raise_for_status()</code></strong> — 4xx/5xx automatically raise a status-keyed exception tree (<code>NotFoundError</code>, <code>RateLimitedError</code>, …), all under <code>httpware.StatusError</code>.</li>
952
+
<li><strong>Typed response bodies</strong> — <code>response_model=YourType</code> decodes the body straight to your pydantic or msgspec model; a missing decoder fails fast, <em>before</em> the request goes out.</li>
953
+
<li><strong>Production resilience as composable middleware</strong> — retry + retry-budget, bulkhead, circuit breaker, and timeout, composed at construction — all over standard <code>httpx2</code>.</li>
954
+
</ul>
927
955
<blockquote>
928
956
<p><strong>Status:</strong> Pre-1.0. Public API is subject to change between minor releases until v1.0.</p>
@@ -978,7 +978,7 @@ <h2 id="when-not-to-write-a-middleware">When NOT to write a middleware<a class="
978
978
<li><strong>Redaction:</strong> Use a <code>logging.Filter</code> on the consumer side. <code>httpware</code> deliberately does no redaction in-library (per the 0.6.0 observability design).</li>
979
979
<li><strong>URL or header validation:</strong><code>httpx2</code> owns it. Don't reimplement.</li>
980
980
<li><strong>Per-call behavior that doesn't apply to other calls:</strong> Pass through <code>request.extensions=</code> (or the <code>extensions=</code> kwarg at the call site) instead. Middleware exists for <em>cross-cutting</em> concerns.</li>
981
-
<li><strong>HTTP-level span creation for tracing:</strong> Install <code>opentelemetry-instrumentation-httpx</code> instead of writing an OTel middleware in httpware. We retired story <code>5-4</code> (standalone OTel middleware) for this reason — <code>opentelemetry-instrumentation-httpx</code> already covers transport-level tracing, and a separate httpware layer would duplicate it. See <code>architecture/middleware.md</code>.</li>
981
+
<li><strong>HTTP-level span creation for tracing:</strong> Install <code>opentelemetry-instrumentation-httpx</code> instead of writing an OTel middleware in httpware. We retired story <code>5-4</code> (standalone OTel middleware) for this reason — <code>opentelemetry-instrumentation-httpx</code> already covers transport-level tracing, and a separate httpware layer would duplicate it. See <ahref="https://github.com/modern-python/httpware/blob/main/architecture/middleware.md"><code>architecture/middleware.md</code></a>.</li>
<p><code>httpware[otel]</code> only ships <code>opentelemetry-api</code>. To make the observability events emitted by <code>AsyncRetry</code> and <code>AsyncBulkhead</code> visible, you also need:</p>
<p>Sync and async middleware classes do not interop: a <code>Middleware</code> cannot be passed to <code>AsyncClient(middleware=...)</code> and vice versa. Pick the flavor matching your client.</p>
<li><strong><code>architecture/middleware.md</code> (Seam A)</strong> — the formal protocol contract and why the chain is frozen at construction.</li>
1052
+
<li><strong><ahref="https://github.com/modern-python/httpware/blob/main/architecture/middleware.md"><code>architecture/middleware.md</code></a> (Seam A)</strong> — the formal protocol contract and why the chain is frozen at construction.</li>
1053
1053
<li><strong><code>src/httpware/middleware/resilience/</code></strong> — <code>AsyncRetry</code>, <code>AsyncBulkhead</code>, <code>RetryBudget</code> as real-world consumers of this exact protocol.</li>
0 commit comments