## Summary
New `enable_logging=True` parameter on `responder.API()` that provides
structured, request-scoped logging using stdlib `logging` and
`contextvars`.
### What it does
- **`api.log`** — always available on every API instance. Works as a
plain logger by default; gains per-request context enrichment with
`enable_logging=True`
- **Per-request context** — every log message automatically includes
request ID, HTTP method, path, and client IP
- **Access logging** — logs every request with timing: `GET /path → 200
(1.2ms)`
- **Request ID** — generates or forwards `X-Request-ID` headers
(supersedes `request_id=True` when both are set)
- **stdlib logging** — works with any existing handler, formatter, or
log aggregator
### Usage
```python
# api.log always works — no setup required
api = responder.API()
api.log.info("starting up") # plain logger, no context
# With enable_logging=True, log messages get request context automatically
api = responder.API(enable_logging=True)
@api.route("/")
def index(req, resp):
api.log.info("handling request")
# => 2026-03-24 12:00:00 [INFO] responder.app — handling request [GET /] [req:abc123] [client:127.0.0.1]
```
For additional loggers in helper modules:
```python
from responder.ext.logging import get_logger
logger = get_logger("myapp.db")
```
### Architecture
- `responder/ext/logging.py` — self-contained module with:
- `LoggingMiddleware` — pure ASGI middleware that sets contextvars and
logs access
- `RequestContextFilter` — logging filter that injects context into
records
- `RequestContext` — read-only access to current request metadata
- `get_logger()` / `setup_logging()` — convenience functions
- `api.log` — always a valid logger; context-aware when
`enable_logging=True`, plain stdlib logger otherwise
- Wired into `API.__init__` via the `enable_logging` parameter
### Files
- `responder/ext/logging.py` — new module
- `responder/api.py` — added `enable_logging` parameter and `api.log`
- `tests/test_logging.py` — 9 tests
- `docs/source/tour.rst` — new Structured Logging section
- `docs/source/index.rst` — added to feature list
## Test plan
- [x] 9 logging tests pass
- [x] Full suite: 208 passed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary
- **Auth tutorial**: fix deprecated `datetime.utcnow()` →
`datetime.now(timezone.utc)`, add role-based access control section, add
auth strategy comparison guide
- **WebSocket tutorial**: use `WebSocketDisconnect` instead of bare
`Exception` in chat example, add connection lifecycle section with close
codes, add rejected connection test example
- **SQLAlchemy tutorial**: modernize from `Column()` to
`mapped_column()` / `Mapped[]` (SQLAlchemy 2.0 style with type checker
support)
- **Deployment**: use `uv` in Docker example instead of pip, fix stale
`uv.lock` reference in production checklist
- **Quickstart**: link to all tutorials in "next steps" (was only
linking to 3 of 9)
- **Sandbox**: rewrite with project layout tree, mypy command, and
pattern-matching test examples
## Test plan
- [x] `make html` builds cleanly
- [x] All 199 tests pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## 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>
- 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>
- 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>
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>
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>
A few of the adjustments here have been required to mitigate Sphinx
warnings, which would converge to errors on CI, thus failing the build.
A few other changes, both wording and syntax/formatting fixes, are
coming from regular copyediting and documentation maintenance.
Basically linked things I had to google/look up on my own. There are a million things that _could_ be linked, but using myself as a median Python coder, it seems about right. Removed italics because I can't figure out how to use them with a link.