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
docs(index): extract pagination recipe and restructure Errors blurb
Quick-Start was carrying a ~37-line `send_with_response` walkthrough that
is really a use-case recipe — moves to `docs/recipes/link-header-pagination.md`
under the existing Recipes nav group, framed around RFC 5988 Link pagination
with `send_with_response` as the mechanism. Quick-Start keeps a one-sentence
pointer next to the typed-decoding example.
The landing-page `## Errors` section was a single dense paragraph cataloging
six exception classes across three categories — replaced with a four-bullet
scan list (status / transport / resilience / decode) and a link to the full
`errors.md` reference.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/index.md
+10-39Lines changed: 10 additions & 39 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -62,6 +62,8 @@ async def main() -> None:
62
62
print(user.name)
63
63
```
64
64
65
+
Need the raw response **and** a decoded body from the same call (e.g., for header-based pagination)? See [Link header pagination](recipes/link-header-pagination.md) — it uses `send_with_response`.
66
+
65
67
### With resilience middleware
66
68
67
69
Compose resilience middleware at construction; `AsyncBulkhead` goes outside `AsyncRetry` so one slot covers all retry attempts.
@@ -81,44 +83,6 @@ async def main() -> None:
81
83
user =await client.get("/users/1", response_model=User)
82
84
```
83
85
84
-
### Response metadata + typed body
85
-
86
-
When you need both the raw `httpx2.Response` (for headers, status, or the
87
-
request URL) **and** a typed body, use `send_with_response`. It returns
88
-
both atomically and routes the decode through the configured
89
-
`ResponseDecoder`, so decoder failures surface as `DecodeError` — caught
90
-
by `except httpware.ClientError` like every other failure mode.
91
-
92
-
Canonical use case: RFC 5988 Link header pagination.
93
-
94
-
Assume `process` and `next_link` are caller-defined — pick a Link header parser that fits.
95
-
96
-
```python
97
-
from httpware import AsyncClient
98
-
from pydantic import BaseModel
99
-
100
-
101
-
classTag(BaseModel):
102
-
name: str
103
-
104
-
105
-
asyncdefmain() -> None:
106
-
asyncwith AsyncClient(base_url="https://gitlab.example/api/v4") as client:
For body-only with a high-level verb, prefer `client.get(..., response_model=...)`.
119
-
For body-only with a custom `Request`, prefer `client.send(request, response_model=...)`.
120
-
`send_with_response` is not for streaming responses — use `stream()`.
121
-
122
86
### Streaming responses
123
87
124
88
For large responses or server-sent events, stream the body chunk-by-chunk. `stream()` is an async context manager:
@@ -140,7 +104,14 @@ It does NOT pass through the middleware chain: `AsyncRetry`, `AsyncBulkhead`, an
140
104
141
105
## Errors
142
106
143
-
All 4xx/5xx responses raise typed exceptions automatically: `NotFoundError`, `ServiceUnavailableError`, `RateLimitedError`, etc. — all subclasses of `httpware.StatusError`. Transport-layer transient failures raise `NetworkError`; the resilience middleware raise `RetryBudgetExhaustedError` and `BulkheadFullError`. Everything inherits `httpware.ClientError`.
107
+
All errors inherit `httpware.ClientError`. The categories:
108
+
109
+
-**Status errors** (4xx/5xx responses) — raised automatically, no `raise_for_status()` needed: `NotFoundError`, `RateLimitedError`, `ServiceUnavailableError`, and the rest. All subclass `StatusError`.
110
+
-**Transport errors** — connection / network / protocol failures before a response arrived. `NetworkError` (transient) subclasses `TransportError`.
111
+
-**Resilience refusals** — `RetryBudgetExhaustedError` and `BulkheadFullError`, raised by the resilience middleware.
GitLab, GitHub, and other APIs paginate via the [RFC 5988](https://datatracker.ietf.org/doc/html/rfc5988)`Link` response header: each page response carries a `Link: <…>; rel="next"` header pointing to the next page. To walk all pages you need both the decoded body **and** the response headers from the same call — `client.get(..., response_model=...)` returns only the body.
4
+
5
+
`send_with_response` returns both atomically. It routes the decoded body through the configured `ResponseDecoder`, so decoder failures surface as `DecodeError` — caught by `except httpware.ClientError` like every other failure mode.
6
+
7
+
## The pagination loop
8
+
9
+
```python
10
+
from httpware import AsyncClient
11
+
from pydantic import BaseModel
12
+
13
+
14
+
classTag(BaseModel):
15
+
name: str
16
+
17
+
18
+
asyncdefmain() -> None:
19
+
asyncwith AsyncClient(base_url="https://gitlab.example/api/v4") as client:
`process` and `next_link` are caller-defined. Pick a Link-header parser that fits your project — there are several on PyPI, and the format is small enough to hand-roll.
0 commit comments