responder 9.2.0


pip install responder

  Latest version

Released: Jul 14, 2026


Meta
Author: Kenneth Reitz
Requires Python: >=3.11

Classifiers

Development Status
  • 5 - Production/Stable

Environment
  • Web Environment

Intended Audience
  • Developers

Operating System
  • OS Independent

Programming Language
  • Python
  • Python :: 3 :: Only
  • Python :: 3.11
  • Python :: 3.12
  • Python :: 3.13
  • Python :: 3.14
  • Python :: 3.15
  • Python :: Free Threading
  • Python :: Implementation :: CPython

Topic
  • Internet :: WWW/HTTP

Responder

Web services for humans.
A familiar HTTP Service Framework for Python, powered by Starlette.

PyPI Python versions License

Documentation · Quickstart · Tour · Examples · Changelog

import responder

api = responder.API()


@api.get("/hello/{name}")
def hello(req, resp, *, name):
    resp.media = {"hello": name}


if __name__ == "__main__":
    api.run()
$ pip install responder
$ python app.py

Open http://127.0.0.1:5042/hello/world. That's it.

Responder is the friendly request/response shape of Flask and Falcon, brought to ASGI with Starlette underneath. Every view receives a req and a resp. Read from one, write to the other. Sync and async views both work.

Why Responder?

Responder is for people who like small, expressive web frameworks with real batteries included.

You want Responder gives you
A simple mental model def view(req, resp): ... with mutable request and response objects
Modern Python I/O ASGI, Starlette routing, uvicorn by default, optional Granian
Real API contracts Typed request/response validation and generated OpenAPI 3.0/3.1
Live typed data Validated SSE and NDJSON with streaming generated clients
Pleasant responses resp.text, resp.html, resp.media, resp.file(), resp.problem()
Production ergonomics request IDs, structured logging, rate limiting, health checks, metrics
Safer defaults Problem Details errors, capped request bodies, secure session guidance
Escape hatches mount Flask, Django, WSGI, ASGI apps, or plain routers under one API

The Shape

Routes look like Python strings, because they are meant to be read.

@api.get("/users/{user_id:int}")
def get_user(req, resp, *, user_id):
    resp.media = {"id": user_id, "name": "Ada"}

Write the response you mean:

resp.text = "hello"
resp.html = "<h1>Hello</h1>"
resp.media = {"ok": True}       # JSON by default, YAML/msgpack by negotiation
resp.file("report.pdf")         # content type detected for you
resp.status_code = 201
resp.headers["Location"] = "/items/1"

Read requests without ceremony:

@api.post("/echo")
async def echo(req, resp):
    payload = await req.media()
    resp.media = {"you_sent": payload}

Return values work too, when that style feels right:

@api.get("/ping")
def ping(req, resp):
    return {"pong": True}

A Real Endpoint

Responder can stay tiny, but it does not stop at toy apps.

from pydantic import BaseModel, Field

import responder
from responder.ext.auth import BearerAuth


class ItemIn(BaseModel):
    name: str = Field(min_length=1)
    price: float = Field(gt=0)


class ItemOut(ItemIn):
    id: int


class User(BaseModel):
    name: str
    scopes: list[str]


api = responder.API(
    title="Store API",
    version="1.0",
    openapi="3.1.0",
    docs_route="/docs",
    request_id=True,
)

users = {"secret-token": User(name="Ada", scopes=["items:write"])}
auth = BearerAuth(verify=lambda token: users.get(token), bearer_format="opaque")
writer = api.policy("writer", auth.requires("items:write"))


@api.post(
    "/items",
    auth=writer,
    status_code=201,
    summary="Create an item",
)
def create_item(req, resp, *, item: ItemIn, user) -> ItemOut:
    return ItemOut(id=1, **item.model_dump())

You get validation, auth enforcement, a documented request body, a documented response body, 401/403/422 Problem Details responses, request IDs, and Swagger UI at /docs. The same inference works for collections:

@api.get("/items")
def list_items(req, resp) -> list[ItemOut]:
    return items

Contracts can stream too. Each event is validated and serialized as it is yielded, OpenAPI carries the item schema, and generated clients expose a lazy iterator instead of buffering the response:

from collections.abc import AsyncIterator


@api.sse("/inventory/events", heartbeat=15)
async def inventory_events(
    req, resp
) -> AsyncIterator[responder.SSE[ItemOut]]:
    async for item in inventory.watch():
        yield responder.SSE(item, event="item", id=item.id)


@api.ndjson("/inventory/export")
async def inventory_export(req, resp) -> AsyncIterator[ItemOut]:
    async for item in inventory.all():
        yield item

What's Included

Area Highlights
Routing @api.get, @api.post, route groups, class-based views, typed path convertors
Validation Pydantic body models, query/header/cookie markers, typed response models
OpenAPI OpenAPI 3.0/3.1, Swagger UI, examples, security schemes, generated clients
Responses JSON/YAML/msgpack, files, typed SSE/NDJSON, byte ranges, ETags
Security signed sessions, server-side sessions, CSRF protection, auth helpers, JWT/OAuth2
Operations request IDs, structured access logs, health checks, Prometheus metrics
Limits request body caps, streaming multipart uploads, in-memory/Redis rate limiting
Composition dependencies with teardown, background tasks, WSGI/ASGI mounting, WebSockets
Deployment built-in uvicorn runner, optional Granian, proxy-header support
Testing in-process api.requests and configurable api.test_client(...)

v9 Highlights

Responder 9 tightened the production story while keeping the familiar API:

  • Multipart uploads stream from the wire and spool to disk instead of buffering entire files in memory.
  • Request bodies are capped at 100 MiB by default; pass API(max_request_size=None) for the legacy unlimited behavior.
  • API(csrf=True) adds session-bound CSRF protection for unsafe requests, with per-route opt-outs for webhooks.
  • API(trust_proxy_headers=True) rewrites scheme, host, and client IP from trusted reverse-proxy headers.
  • Framework-generated errors use RFC 9457-style application/problem+json responses by default.
  • OpenAPI documents operational responses such as CSRF 403, body-cap 413, rate-limit 429, fail-closed limiter 503, validation 422, and timeout 504 where they can actually happen.

Upgrading from an earlier major version? Start with the v9 migration guide.

Installation

$ pip install responder

Python 3.11 and newer are supported.

Optional extras:

$ pip install "responder[server]"   # Granian production server
$ pip install "responder[graphql]"  # GraphQL with Graphene
$ pip install "responder[jwt]"      # JWT auth helpers
$ pip install "responder[orjson]"   # orjson JSON backend

With uv:

$ uv add responder

Run It

# app.py
import responder

api = responder.API()


@api.get("/")
def index(req, resp):
    resp.text = "hello, world!"


if __name__ == "__main__":
    api.run(port=8000)
$ python app.py

Or through the CLI:

$ responder run app.py

OpenAPI and Clients

Turn on OpenAPI with two arguments:

api = responder.API(
    title="Acme API",
    version="1.0",
    openapi="3.1.0",
    docs_route="/docs",
)

Responder builds the schema from routes, type hints, Pydantic models, auth helpers, and framework behavior. The docs UI appears at /docs, the schema at /schema.yml, and client code can be generated for Python, JavaScript, TypeScript, Ruby, and PHP.

$ responder client --class-name StoreClient --output store_client.py app:api

Examples Worth Reading

Example Why it is useful
examples/atelier.py The golden contract app: auth, policies, examples, OpenAPI, generated-client coverage
examples/todo.py A practical typed Todo API with protected writes and polished schema metadata
examples/fortunes.py Tiny app wrapping the local fortune CLI tool
examples/tarot.py A playful API that shuffles, lists, and deals tarot cards
examples/sse_stream.py Typed Server-Sent Events with metadata, heartbeats, and OpenAPI
examples/websocket_chat.py WebSocket chat with Responder's route style
examples/marimo_mount.py Mounting a marimo notebook app under Responder

Run most examples with:

$ responder run examples/todo.py

Philosophy

Responder is intentionally familiar. If you know Flask, Falcon, Requests, or Starlette, you already know most of the ideas. The framework tries to make the simple thing feel natural, then keeps enough power nearby for real services: typed contracts, OpenAPI, auth, rate limiting, streaming uploads, websockets, and production middleware.

It is a passion project and a practical toolkit. It is especially good for personal services, internal tools, prototypes, teaching, research apps, and small APIs where clarity matters more than ceremony.

Documentation

The full guide lives at responder.kennethreitz.org.

License

Apache-2.0.

9.2.0 Jul 14, 2026
9.1.0 Jul 12, 2026
9.0.1 Jul 06, 2026
9.0.0 Jul 06, 2026
8.3.0 Jul 05, 2026
8.2.3 Jul 05, 2026
8.2.2 Jul 03, 2026
8.2.1 Jul 03, 2026
8.2.0 Jul 03, 2026
8.1.0 Jul 03, 2026
8.0.2 Jul 03, 2026
8.0.1 Jul 03, 2026
8.0.0 Jul 01, 2026
7.3.0 Jul 01, 2026
7.2.1 Jul 01, 2026
7.2.0 Jul 01, 2026
7.1.3 Jul 01, 2026
7.1.2 Jul 01, 2026
7.1.1 Jun 30, 2026
7.1.0 Jun 30, 2026
7.0.5 Jun 30, 2026
7.0.4 Jun 30, 2026
7.0.3 Jun 30, 2026
7.0.2 Jun 30, 2026
7.0.1 Jun 29, 2026
7.0.0 Jun 29, 2026
6.6.1 Jun 29, 2026
6.6.0 Jun 29, 2026
6.5.3 Jun 29, 2026
6.5.2 Jun 29, 2026
6.5.1 Jun 29, 2026
6.5.0 Jun 29, 2026
6.4.0 Jun 29, 2026
6.3.1 Jun 29, 2026
6.3.0 Jun 29, 2026
6.2.0 Jun 29, 2026
6.1.0 Jun 29, 2026
6.0.2 Jun 29, 2026
6.0.1 Jun 29, 2026
6.0.0 Jun 29, 2026
5.6.0 Jun 29, 2026
5.5.0 Jun 29, 2026
5.4.0 Jun 29, 2026
5.3.0 Jun 29, 2026
5.2.0 Jun 29, 2026
5.1.0 Jun 28, 2026
5.0.0 Jun 28, 2026
4.1.0 Jun 28, 2026
4.0.0 Jun 12, 2026
3.12.0 Jun 12, 2026
3.11.0 Jun 12, 2026
3.10.0 Jun 12, 2026
3.9.1 Jun 12, 2026
3.9.0 Jun 12, 2026
3.8.0 Jun 12, 2026
3.7.0 Jun 12, 2026
3.6.2 Apr 12, 2026
3.6.1 Apr 12, 2026
3.6.0 Mar 24, 2026
3.5.0 Mar 24, 2026
3.4.1 Mar 23, 2026
3.4.0 Mar 23, 2026
3.3.0 Mar 22, 2026
3.2.0 Mar 22, 2026
3.1.0 Mar 22, 2026
3.0.0.dev0 Jan 19, 2025
2.0.7 Jan 08, 2021
2.0.6 Jan 06, 2021
2.0.5 Dec 15, 2019
2.0.4 Nov 19, 2019
2.0.3 Oct 22, 2019
2.0.2 Oct 20, 2019
2.0.1 Oct 20, 2019
2.0.0 Oct 19, 2019
1.3.2 Aug 15, 2019
1.3.1 Apr 28, 2019
1.3.0 Feb 22, 2019
1.2.0 Jan 01, 2019
1.1.3 Jan 12, 2019
1.1.2 Nov 11, 2018
1.1.1 Oct 29, 2018
1.1.0 Oct 27, 2018
1.0.5 Oct 27, 2018
1.0.4 Oct 27, 2018
1.0.3 Oct 27, 2018
1.0.2 Oct 27, 2018
1.0.1 Oct 26, 2018
1.0.0 Oct 26, 2018
0.3.3 Oct 25, 2018
0.3.2 Oct 25, 2018
0.3.1 Oct 24, 2018
0.3.0 Oct 24, 2018
0.2.3 Oct 24, 2018
0.2.2 Oct 23, 2018
0.2.1 Oct 23, 2018
0.2.0 Oct 22, 2018
0.1.6 Oct 20, 2018
0.1.5 Oct 20, 2018
0.1.4 Oct 19, 2018
0.1.3 Oct 18, 2018
0.1.2 Oct 18, 2018
0.1.1 Oct 17, 2018
0.1.0 Oct 17, 2018
0.0.10 Oct 17, 2018
0.0.9 Oct 17, 2018
0.0.8 Oct 17, 2018
0.0.7 Oct 16, 2018
0.0.6 Oct 16, 2018
0.0.5 Oct 15, 2018
0.0.4 Oct 15, 2018
0.0.3 Oct 13, 2018
0.0.2 Oct 13, 2018
0.0.1 Oct 12, 2018
0.0.0 Oct 09, 2018

Wheel compatibility matrix

Platform Python 3
any

Files in release

Extras:
Dependencies:
a2wsgi
apispec (>=6.6)
chardet
docopt-ng
httpx (<0.29,>=0.27)
httpx2 (>=2)
itsdangerous
jinja2 (>=3.1)
marshmallow (>=3.20)
msgpack
pydantic (>=2)
python-multipart (>=0.0.12)
pyyaml (>=6)
starlette (>=1)
uvicorn[standard] (>=0.50)