Skip to content

Commit 1cb87fd

Browse files
authored
Merge pull request #9 from modern-python/story/2-2-phase-shortcut-decorators
feat(story-2.2): phase-shortcut decorators @before_request, @after_response, @on_error
2 parents 2b70dd9 + 164e72d commit 1cb87fd

7 files changed

Lines changed: 1252 additions & 6 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
2020
- `Transport` protocol (`@runtime_checkable`) and default `Httpx2Transport` adapter; `StreamResponse` placeholder for Story 4.1 protocol typing; the wire `method` is uppercased at the seam and `httpx2` exceptions (`TimeoutException`, `HTTPError`, `InvalidURL`, `CookieConflict`, and the closed-client `RuntimeError`) are mapped to `httpware.TimeoutError` / `httpware.TransportError` (with the original exception's message preserved on the mapped instance) so no `httpx2` exception escapes the library; lazy `httpx2.AsyncClient` construction is guarded by an `asyncio.Lock` so concurrent first-calls share one client; `httpx2` is confined to `src/httpware/transports/httpx2.py` (Story 1.4).
2121
- `ResponseDecoder` protocol (`@runtime_checkable`) and default `PydanticDecoder` adapter — single-parse-pass JSON decoding via `pydantic.TypeAdapter.validate_json(bytes)`; a module-level `@functools.lru_cache(maxsize=None)` factory (`_get_adapter`) memoizes one `TypeAdapter` per `response_model` across the process so warm-path requests pay zero adapter-construction cost; `pydantic.ValidationError` surfaces unchanged to the caller (Story 1.5).
2222
- `Middleware` protocol (`@runtime_checkable`) and `Next` callable type alias (`Callable[[Request], Awaitable[Response]]`); private `compose(middlewares, transport)` chain composer at `httpware._internal.chain` using a recursive closure fold with `transport.__call__` as the bottom of the chain. No exception handling inside `compose`, so `asyncio.CancelledError` and user-raised exceptions propagate untouched (Story 2.1).
23+
- Phase-shortcut decorators `@before_request`, `@after_response`, `@on_error` for lifecycle hooks without authoring a full `Middleware` class. `@on_error` catches `Exception` only (so `asyncio.CancelledError` propagates); its handler may return a `Response` to recover or `None` to re-raise (Story 2.2).
2324

2425
[Unreleased]: https://github.com/modern-python/httpware/commits/main

‎docs/engineering.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ Twenty-seven stories remain. Topic slugs in `docs/superpowers/specs/` and `docs/
142142
### Epic 2 — Compose request-handling logic via middleware
143143

144144
- **2-1** `Middleware` protocol, `Next` type, chain composition.
145-
- **2-2** Phase shortcut decorators (`@on_request`, `@on_response`, `@on_error`).
145+
- **2-2** Phase shortcut decorators (`@before_request`, `@after_response`, `@on_error`).
146146
- **2-3** `Request` immutability helpers (`with_headers`, `with_cookie`, `with_extension`, etc.).
147147
- **2-4** Auth coercion as middleware.
148148
- **2-5** Wire middleware into `AsyncClient`.

0 commit comments

Comments
 (0)