## Summary
- **Deployment guide**: health check endpoint, Docker Compose example,
Caddy reverse proxy config, Procfile pattern, production checklist
- **API reference**: quick usage examples for every class (API, Request,
Response, RouteGroup, BackgroundQueue, RateLimiter, status helpers)
- **Feature tour**: new Pydantic validation and content negotiation
sections, expanded MessagePack docs
- **Testing guide**: rate limiting and mounted WSGI app test examples,
Werkzeug 3.1.7 tip
- **Middleware tutorial**: pure ASGI middleware example (no
BaseHTTPMiddleware dependency)
- **CLI guide**: environment variables section (PORT, SECRET_KEY)
- **Homepage**: updated feature list with SSE, rate limiting, Pydantic,
content negotiation, route groups
- **Backlog**: removed already-implemented items, added current ideas
+362 lines of docs, no code changes.
## Test plan
- [x] `make html` builds cleanly with no warnings
- [x] All 199 tests pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Andreas Motl <andreas.motl@panodata.org>
- Call future.result() instead of bare property access in test (#596)
- Catch (ValueError, TypeError) instead of broad Exception in
response model serialization (#597)
- Catch WebSocketDisconnect instead of broad Exception in
websocket chat example (#598)
Closes#596, closes#597, closes#598
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## About
A few cosmetic adjustments aka. code formatting.
Also validate the outcome on CI/GHA.
Feel free to improve now or later at your disposal.
## Details
The updates are based on using the most recent versions of pyproject-fmt
and ruff.
Specifically, spots marked with `noqa` might need further love, also at
your disposal.
---------
Co-authored-by: Kenneth Reitz <me@kennethreitz.org>
## Summary
- When a WSGI app (e.g. Flask) is mounted at `/prefix` and a request
hits exactly `/prefix`, the path prefix was stripped to `""` instead of
`"/"`, causing frameworks like Flask to return 400.
- One-character fix: default the stripped path to `"/"` when empty.
## Test plan
- [x] `tests/test_responder.py::test_mount_wsgi_app` now passes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Document mounting marimo ASGI apps in the feature tour
- Add examples/marimo_mount.py showing the integration
- Verified working: marimo.create_asgi_app() mounts cleanly via api.mount()
Fixes#580.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract variables and operationName from query params and form data,
not just JSON bodies. Fixes#571.
- Add docstrings to GraphQLView class and methods. Fixes#572.
- Add 10 new GraphQL tests: variables, operationName, mutations,
context access, malformed queries, raw text, invalid variables
param. Fixes#568.
- Remove Python 3.9 from CI matrix (dropped in 3.4.0).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add comprehensive type hints to compile_path, BaseRoute, Route,
WebSocketRoute, and Router classes. Uses Starlette's Scope, Receive,
Send types and properly types the ASGI/WSGI union in Router.apps.
Fixes#566.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Include ext/openapi/docs/*.html in package_data so OpenAPI docs
themes (swagger_ui, redoc, rapidoc, elements) ship with the wheel.
Fixes#583.
- Add tests for static file serving and index.html fallback. Fixes#563.
- Bump version to 3.4.1.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add docstrings to all undocumented public methods across API, Request,
Response, Router, Route, BackgroundQueue, and related classes
- Expand api.rst with autodoc sections for RouteGroup, BackgroundQueue,
QueryDict, and RateLimiter
- Update starlette dependency to >=1.0
- Drop Python 3.9 support (required by Starlette 1.0), minimum is now 3.10
- Bump version to 3.4.0
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New documentation pages:
- Authentication: API keys, JWT tokens, session auth, custom exceptions
- WebSocket Tutorial: echo server, chat room, HTML client, data formats
- Writing Middleware: hooks vs middleware, Starlette integration, ordering
- Configuration: env vars, .env files, secret keys, debug mode, production setup
Also:
- Complete working example at end of quickstart with cross-references
- Three new example files: rest_api.py, websocket_chat.py, sse_stream.py
- Changelog updated for v3.2.0
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three new tutorial pages:
- Building a REST API: full CRUD with Pydantic validation, from scratch
- Using SQLAlchemy: async engine, lifespan setup, CRUD with ORM
- Migrating from Flask: concept mapping, quick reference table,
gradual migration via app mounting
Also rewritten:
- CLI docs: cleaner, more concise
- API reference: added prose descriptions for each section
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Every section now teaches web development concepts alongside the code:
- HTTP methods, status codes, content negotiation explained
- What ASGI is and why it matters
- How cookies, sessions, CORS, and HSTS work
- When to use WebSockets vs SSE
- Why request validation matters
- How background tasks differ from task queues
- What rate limiting protects against
- What Host header injection is
- Separation of concerns in templating
People should learn about web development while reading these docs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New sections: request validation, headers/cookies, custom error
handlers, before/after hooks, and practical tips. Every section
now explains the why, not just the how.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New features:
- Request ID: api = responder.API(request_id=True)
- Rate limiting: RateLimiter(requests=100, period=60).install(api)
- MessagePack format: await req.media("msgpack")
- All new features documented in tour
176 tests, 95% coverage.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Five new features:
1. **Pydantic auto-validation** — if request_model is set, request
bodies are validated automatically and 422 returned on failure.
If response_model is set, resp.media is serialized through the
model (extra fields stripped, types enforced).
2. **Server-Sent Events** — resp.sse for real-time streaming:
@resp.sse
async def stream():
yield {"event": "update", "data": "hello"}
3. **resp.stream_file()** — stream large files without loading
into memory, with automatic content-type detection.
4. **after_request hooks** — run code after every request:
@api.after_request()
def add_request_id(req, resp):
resp.headers["X-Request-ID"] = str(uuid.uuid4())
5. **Route groups** — organize routes with shared prefixes:
v1 = api.group("/v1")
@v1.route("/users")
def list_users(req, resp): ...
Also fix streaming responses not sending Content-Type headers.
172 tests, 95% coverage.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three approaches: Pydantic models (recommended), YAML docstrings,
and marshmallow schemas — all work together.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Define your API schemas with Pydantic models instead of (or alongside)
YAML docstrings and marshmallow:
from pydantic import BaseModel
class PetIn(BaseModel):
name: str
age: int = 0
class PetOut(BaseModel):
id: int
name: str
age: int
@api.route("/pets", methods=["POST"],
request_model=PetIn, response_model=PetOut)
async def create_pet(req, resp):
data = await req.media()
resp.media = {"id": 1, **data}
Also works with @api.schema("Name") decorator for registering
standalone schema components.
Pydantic models, marshmallow schemas, and YAML docstrings can all
be used together in the same API.
Also: rewrite docs with more prose, restore sidebar logo and links,
add FastAPI acknowledgment, update homepage copy.
161 tests, 95% coverage.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Clean, code-first README. No badges, no testimonials — just
show what the framework does with real examples.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace all poe task runner usage with direct pytest/sphinx/ruff
commands. Remove poethepoet dependency and [tool.poe.tasks] config.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove commented-out tests (route overlap, form data, file uploads)
- Remove stale TODO/FIXME comments from routes.py and api.py
- Make CLI npm error assertions case-insensitive and more flexible
to handle different npm versions across CI environments
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace with stdlib urllib.request. No third-party HTTP client
needed for test probing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reflect all changes made in this branch: dependency reduction,
GraphQL modernization, pyproject.toml migration, etc. Also fix
compare links to point to kennethreitz/responder.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All package metadata now lives in pyproject.toml. Removes setup.py
and MANIFEST.in. Also exports __version__ from the package root.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace rfc3986 with stdlib urllib.parse
- Remove deprecated status code aliases (resume_incomplete/resume)
that were marked for removal in 3.0
- Remove private ThreadPoolExecutor API usage in BackgroundQueue
- Clean up stale comments (old Starlette PR refs, requests attribution)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove `requests` as a core dependency — replaced CaseInsensitiveDict
and RequestsCookieJar with lightweight stdlib implementations
- Remove `requests-toolbelt` — replaced multipart decoder with
python-multipart (already a starlette transitive dep)
- Upgrade GraphQL to graphene 3 + graphql-core 3, drop graphql-server-core
- Update GraphiQL template from 0.12.0 (2018) to 3.0.6 with React 18
- Clean up setup.py: remove dead DebCommand, UploadCommand, publish hack
- Remove linting from `poe check` (tests only)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>