Skip to content

Commit d8d5f26

Browse files
author
committed
Deployed 480cea8 with MkDocs version: 1.6.1
1 parent 4c08266 commit d8d5f26

11 files changed

Lines changed: 142 additions & 114 deletions

File tree

404.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,14 +274,14 @@
274274

275275

276276
<li class="md-nav__item">
277-
<a href="/resilience/" class="md-nav__link">
277+
<a href="/middleware/" class="md-nav__link">
278278

279279

280280

281281
<span class="md-ellipsis">
282282

283283

284-
Resilience
284+
Middleware
285285

286286

287287

@@ -301,14 +301,14 @@
301301

302302

303303
<li class="md-nav__item">
304-
<a href="/middleware/" class="md-nav__link">
304+
<a href="/resilience/" class="md-nav__link">
305305

306306

307307

308308
<span class="md-ellipsis">
309309

310310

311-
Middleware
311+
Resilience
312312

313313

314314

dev/contributing/index.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -283,14 +283,14 @@
283283

284284

285285
<li class="md-nav__item">
286-
<a href="../../resilience/" class="md-nav__link">
286+
<a href="../../middleware/" class="md-nav__link">
287287

288288

289289

290290
<span class="md-ellipsis">
291291

292292

293-
Resilience
293+
Middleware
294294

295295

296296

@@ -310,14 +310,14 @@
310310

311311

312312
<li class="md-nav__item">
313-
<a href="../../middleware/" class="md-nav__link">
313+
<a href="../../resilience/" class="md-nav__link">
314314

315315

316316

317317
<span class="md-ellipsis">
318318

319319

320-
Middleware
320+
Resilience
321321

322322

323323

errors/index.html

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<link rel="canonical" href="https://httpware.modern-python.org/errors/">
1212

1313

14-
<link rel="prev" href="../middleware/">
14+
<link rel="prev" href="../resilience/">
1515

1616

1717
<link rel="next" href="../testing/">
@@ -285,14 +285,14 @@
285285

286286

287287
<li class="md-nav__item">
288-
<a href="../resilience/" class="md-nav__link">
288+
<a href="../middleware/" class="md-nav__link">
289289

290290

291291

292292
<span class="md-ellipsis">
293293

294294

295-
Resilience
295+
Middleware
296296

297297

298298

@@ -312,14 +312,14 @@
312312

313313

314314
<li class="md-nav__item">
315-
<a href="../middleware/" class="md-nav__link">
315+
<a href="../resilience/" class="md-nav__link">
316316

317317

318318

319319
<span class="md-ellipsis">
320320

321321

322-
Middleware
322+
Resilience
323323

324324

325325

@@ -1093,7 +1093,7 @@ <h2 id="see-also">See also<a class="headerlink" href="#see-also" title="Permanen
10931093
<ul>
10941094
<li><strong><a href="../resilience/">Resilience reference</a></strong><code>AsyncRetry</code>, <code>RetryBudget</code>, <code>AsyncBulkhead</code> parameter tables.</li>
10951095
<li><strong><a href="../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><a href="https://github.com/modern-python/httpware/blob/main/architecture/errors.md"><code>architecture/errors.md</code></a></strong> — the formal exception contract.</li>
10971097
</ul>
10981098

10991099

@@ -1130,7 +1130,7 @@ <h2 id="see-also">See also<a class="headerlink" href="#see-also" title="Permanen
11301130
<nav class="md-footer__inner md-grid" aria-label="Footer" >
11311131

11321132

1133-
<a href="../middleware/" class="md-footer__link md-footer__link--prev" aria-label="Previous: Middleware">
1133+
<a href="../resilience/" class="md-footer__link md-footer__link--prev" aria-label="Previous: Resilience">
11341134
<div class="md-footer__button md-icon">
11351135

11361136
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
@@ -1140,7 +1140,7 @@ <h2 id="see-also">See also<a class="headerlink" href="#see-also" title="Permanen
11401140
Previous
11411141
</span>
11421142
<div class="md-ellipsis">
1143-
Middleware
1143+
Resilience
11441144
</div>
11451145
</div>
11461146
</a>

index.html

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313

1414

15-
<link rel="next" href="resilience/">
15+
<link rel="next" href="middleware/">
1616

1717

1818

@@ -315,6 +315,17 @@
315315
</label>
316316
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
317317

318+
<li class="md-nav__item">
319+
<a href="#why-httpware" class="md-nav__link">
320+
<span class="md-ellipsis">
321+
322+
Why httpware
323+
324+
</span>
325+
</a>
326+
327+
</li>
328+
318329
<li class="md-nav__item">
319330
<a href="#install" class="md-nav__link">
320331
<span class="md-ellipsis">
@@ -435,14 +446,14 @@
435446

436447

437448
<li class="md-nav__item">
438-
<a href="resilience/" class="md-nav__link">
449+
<a href="middleware/" class="md-nav__link">
439450

440451

441452

442453
<span class="md-ellipsis">
443454

444455

445-
Resilience
456+
Middleware
446457

447458

448459

@@ -462,14 +473,14 @@
462473

463474

464475
<li class="md-nav__item">
465-
<a href="middleware/" class="md-nav__link">
476+
<a href="resilience/" class="md-nav__link">
466477

467478

468479

469480
<span class="md-ellipsis">
470481

471482

472-
Middleware
483+
Resilience
473484

474485

475486

@@ -792,6 +803,17 @@
792803
</label>
793804
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
794805

806+
<li class="md-nav__item">
807+
<a href="#why-httpware" class="md-nav__link">
808+
<span class="md-ellipsis">
809+
810+
Why httpware
811+
812+
</span>
813+
</a>
814+
815+
</li>
816+
795817
<li class="md-nav__item">
796818
<a href="#install" class="md-nav__link">
797819
<span class="md-ellipsis">
@@ -924,6 +946,12 @@
924946

925947
<h1 id="httpware">httpware<a class="headerlink" href="#httpware" title="Permanent link">&para;</a></h1>
926948
<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>
949+
<h2 id="why-httpware">Why httpware<a class="headerlink" href="#why-httpware" title="Permanent link">&para;</a></h2>
950+
<ul>
951+
<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>
927955
<blockquote>
928956
<p><strong>Status:</strong> Pre-1.0. Public API is subject to change between minor releases until v1.0.</p>
929957
</blockquote>
@@ -942,17 +970,17 @@ <h2 id="first-request">First request<a class="headerlink" href="#first-request"
942970
<a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a><span class="kn">from</span><span class="w"> </span><span class="nn">httpware</span><span class="w"> </span><span class="kn">import</span> <span class="n">AsyncClient</span>
943971
<a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a>
944972
<a id="__codelineno-2-5" name="__codelineno-2-5" href="#__codelineno-2-5"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">main</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
945-
<a id="__codelineno-2-6" name="__codelineno-2-6" href="#__codelineno-2-6"></a> <span class="k">async</span> <span class="k">with</span> <span class="n">AsyncClient</span><span class="p">(</span><span class="n">base_url</span><span class="o">=</span><span class="s2">&quot;https://example.test&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">client</span><span class="p">:</span>
946-
<a id="__codelineno-2-7" name="__codelineno-2-7" href="#__codelineno-2-7"></a> <span class="n">response</span> <span class="o">=</span> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;/users/42&quot;</span><span class="p">)</span>
973+
<a id="__codelineno-2-6" name="__codelineno-2-6" href="#__codelineno-2-6"></a> <span class="k">async</span> <span class="k">with</span> <span class="n">AsyncClient</span><span class="p">(</span><span class="n">base_url</span><span class="o">=</span><span class="s2">&quot;https://jsonplaceholder.typicode.com&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">client</span><span class="p">:</span>
974+
<a id="__codelineno-2-7" name="__codelineno-2-7" href="#__codelineno-2-7"></a> <span class="n">response</span> <span class="o">=</span> <span class="k">await</span> <span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;/users/1&quot;</span><span class="p">)</span>
947975
<a id="__codelineno-2-8" name="__codelineno-2-8" href="#__codelineno-2-8"></a> <span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">json</span><span class="p">())</span>
948976
<a id="__codelineno-2-9" name="__codelineno-2-9" href="#__codelineno-2-9"></a>
949977
<a id="__codelineno-2-10" name="__codelineno-2-10" href="#__codelineno-2-10"></a><span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
950978
</code></pre></div>
951979
<p><strong>Sync usage:</strong></p>
952980
<div class="highlight"><pre><span></span><code><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">httpware</span><span class="w"> </span><span class="kn">import</span> <span class="n">Client</span>
953981
<a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a>
954-
<a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="k">with</span> <span class="n">Client</span><span class="p">(</span><span class="n">base_url</span><span class="o">=</span><span class="s2">&quot;https://example.test&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">client</span><span class="p">:</span>
955-
<a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a> <span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;/users/42&quot;</span><span class="p">)</span>
982+
<a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="k">with</span> <span class="n">Client</span><span class="p">(</span><span class="n">base_url</span><span class="o">=</span><span class="s2">&quot;https://jsonplaceholder.typicode.com&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">client</span><span class="p">:</span>
983+
<a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a> <span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;/users/1&quot;</span><span class="p">)</span>
956984
<a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a> <span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">json</span><span class="p">())</span>
957985
</code></pre></div>
958986
<p>Typed decoding via <code>response_model=</code> works the same way in both worlds:</p>
@@ -1123,13 +1151,13 @@ <h2 id="part-of-modern-python">Part of <code>modern-python</code><a class="heade
11231151

11241152

11251153

1126-
<a href="resilience/" class="md-footer__link md-footer__link--next" aria-label="Next: Resilience">
1154+
<a href="middleware/" class="md-footer__link md-footer__link--next" aria-label="Next: Middleware">
11271155
<div class="md-footer__title">
11281156
<span class="md-footer__direction">
11291157
Next
11301158
</span>
11311159
<div class="md-ellipsis">
1132-
Resilience
1160+
Middleware
11331161
</div>
11341162
</div>
11351163
<div class="md-footer__button md-icon">

middleware/index.html

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111
<link rel="canonical" href="https://httpware.modern-python.org/middleware/">
1212

1313

14-
<link rel="prev" href="../resilience/">
14+
<link rel="prev" href="..">
1515

1616

17-
<link rel="next" href="../errors/">
17+
<link rel="next" href="../resilience/">
1818

1919

2020

@@ -282,33 +282,6 @@
282282

283283

284284

285-
286-
287-
<li class="md-nav__item">
288-
<a href="../resilience/" class="md-nav__link">
289-
290-
291-
292-
<span class="md-ellipsis">
293-
294-
295-
Resilience
296-
297-
298-
299-
</span>
300-
301-
302-
303-
</a>
304-
</li>
305-
306-
307-
308-
309-
310-
311-
312285

313286

314287

@@ -462,6 +435,33 @@
462435

463436

464437

438+
<li class="md-nav__item">
439+
<a href="../resilience/" class="md-nav__link">
440+
441+
442+
443+
<span class="md-ellipsis">
444+
445+
446+
Resilience
447+
448+
449+
450+
</span>
451+
452+
453+
454+
</a>
455+
</li>
456+
457+
458+
459+
460+
461+
462+
463+
464+
465465
<li class="md-nav__item">
466466
<a href="../errors/" class="md-nav__link">
467467

@@ -978,7 +978,7 @@ <h2 id="when-not-to-write-a-middleware">When NOT to write a middleware<a class="
978978
<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>
979979
<li><strong>URL or header validation:</strong> <code>httpx2</code> owns it. Don't reimplement.</li>
980980
<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 <a href="https://github.com/modern-python/httpware/blob/main/architecture/middleware.md"><code>architecture/middleware.md</code></a>.</li>
982982
</ul>
983983
<h2 id="wiring-opentelemetry">Wiring OpenTelemetry<a class="headerlink" href="#wiring-opentelemetry" title="Permanent link">&para;</a></h2>
984984
<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>
@@ -1049,7 +1049,7 @@ <h2 id="sync-middleware">Sync middleware<a class="headerlink" href="#sync-middle
10491049
<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>
10501050
<h2 id="see-also">See also<a class="headerlink" href="#see-also" title="Permanent link">&para;</a></h2>
10511051
<ul>
1052-
<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><a href="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>
10531053
<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>
10541054
<li><strong><a href="../#with-resilience-middleware">Quick-Start composition example</a></strong> — composing built-in middleware.</li>
10551055
</ul>
@@ -1088,7 +1088,7 @@ <h2 id="see-also">See also<a class="headerlink" href="#see-also" title="Permanen
10881088
<nav class="md-footer__inner md-grid" aria-label="Footer" >
10891089

10901090

1091-
<a href="../resilience/" class="md-footer__link md-footer__link--prev" aria-label="Previous: Resilience">
1091+
<a href=".." class="md-footer__link md-footer__link--prev" aria-label="Previous: Quick-Start">
10921092
<div class="md-footer__button md-icon">
10931093

10941094
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
@@ -1098,20 +1098,20 @@ <h2 id="see-also">See also<a class="headerlink" href="#see-also" title="Permanen
10981098
Previous
10991099
</span>
11001100
<div class="md-ellipsis">
1101-
Resilience
1101+
Quick-Start
11021102
</div>
11031103
</div>
11041104
</a>
11051105

11061106

11071107

1108-
<a href="../errors/" class="md-footer__link md-footer__link--next" aria-label="Next: Errors">
1108+
<a href="../resilience/" class="md-footer__link md-footer__link--next" aria-label="Next: Resilience">
11091109
<div class="md-footer__title">
11101110
<span class="md-footer__direction">
11111111
Next
11121112
</span>
11131113
<div class="md-ellipsis">
1114-
Errors
1114+
Resilience
11151115
</div>
11161116
</div>
11171117
<div class="md-footer__button md-icon">

0 commit comments

Comments
 (0)