Files
responder/changes.html
2026-07-17 21:00:53 +00:00

3117 lines
298 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en" data-content_root="./">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Changelog &#8212; responder 9.2.0 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=5ecbeea2" />
<link rel="stylesheet" type="text/css" href="_static/basic.css?v=b08954a9" />
<link rel="stylesheet" type="text/css" href="_static/alabaster.css?v=eb4102c5" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
<link rel="stylesheet" type="text/css" href="_static/sphinx-design.min.css?v=95c83b7e" />
<link rel="stylesheet" type="text/css" href="_static/design-elements.e5416f61bae5d36adc6d722a2b6f8cff.css?v=452a8e97" />
<script src="_static/documentation_options.js?v=e8b940be"></script>
<script src="_static/doctools.js?v=fd6eb6e6"></script>
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
<script src="_static/copybutton.js?v=fd10adb8"></script>
<script>
</script>
<script src="_static/design-tabs.js?v=f930bc37"></script>
<script src="_static/design-elements.bbdccc18c4abea9397628f9fea3d48c2.js?v=03c7770e"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Migrating to v9" href="migration-v9.html" />
<link rel="prev" title="Runtime Contracts" href="runtime-contracts.html" />
<link rel="stylesheet" href="_static/custom.css" type="text/css" />
</head><body>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section id="changelog">
<h1>Changelog<a class="headerlink" href="#changelog" title="Link to this heading"></a></h1>
<p>All notable changes to this project will be documented in this file.</p>
<p>The format is based on <a class="reference external" href="https://keepachangelog.com/en/1.0.0/">Keep a Changelog</a>, and
this project adheres to <a class="reference external" href="https://semver.org/spec/v2.0.0.html">Semantic Versioning</a>.</p>
<section id="unreleased">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v9.2.0..HEAD">Unreleased</a><a class="headerlink" href="#unreleased" title="Link to this heading"></a></h2>
<section id="changed">
<h3>Changed<a class="headerlink" href="#changed" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Installation documentation now recommends <code class="docutils literal notranslate"><span class="pre">responder[orjson]</span></code> on
standard GIL-enabled CPython, including combined feature extras and
deployment examples. Bare <code class="docutils literal notranslate"><span class="pre">responder</span></code> remains the compatibility install
for free-threaded interpreters and transparently uses the standard-library
JSON encoder when orjson is unavailable.</p></li>
</ul>
</section>
</section>
<section id="v9-2-0-2026-07-14">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v9.1.0..v9.2.0">v9.2.0</a> - 2026-07-14<a class="headerlink" href="#v9-2-0-2026-07-14" title="Link to this heading"></a></h2>
<p>Responder 9.2 makes typed SSE and NDJSON complete incremental response
contracts, from per-item runtime validation through OpenAPI and generated
streaming clients.</p>
<section id="added">
<h3>Added<a class="headerlink" href="#added" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Typed event streams: <code class="docutils literal notranslate"><span class="pre">&#64;api.sse</span></code> and <code class="docutils literal notranslate"><span class="pre">&#64;api.ndjson</span></code> infer item contracts
from sync or async iterator return annotations (or explicit
<code class="docutils literal notranslate"><span class="pre">event_model=</span></code> / <code class="docutils literal notranslate"><span class="pre">item_model=</span></code>), validate and serialize every yielded
item with Pydantic, and preserve backpressure and cancellation cleanup.
<code class="docutils literal notranslate"><span class="pre">responder.SSE[T]</span></code> adds typed <code class="docutils literal notranslate"><span class="pre">data</span></code> plus standard <code class="docutils literal notranslate"><span class="pre">event</span></code>, <code class="docutils literal notranslate"><span class="pre">id</span></code>, <code class="docutils literal notranslate"><span class="pre">retry</span></code>,
and comment metadata; SSE routes retain heartbeats and <code class="docutils literal notranslate"><span class="pre">Last-Event-ID</span></code>
support.</p></li>
<li><p>OpenAPI now documents typed streams with their wire media type and item
schema. Generated Python, JavaScript, TypeScript, Ruby, and PHP clients
consume them lazily as iterators, including typed SSE metadata events.</p></li>
</ul>
</section>
<section id="id1">
<h3>Changed<a class="headerlink" href="#id1" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>An immediately available first stream item is validated before response
headers, allowing contract failures to return <code class="docutils literal notranslate"><span class="pre">500</span></code>. Failures after a
stream begins are logged and terminate it without emitting the invalid
item. <code class="docutils literal notranslate"><span class="pre">HEAD</span></code> remains body-free and does not start the producer.</p></li>
</ul>
</section>
</section>
<section id="v9-1-0-2026-07-12">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v9.0.1..v9.1.0">v9.1.0</a> - 2026-07-12<a class="headerlink" href="#v9-1-0-2026-07-12" title="Link to this heading"></a></h2>
<p>Responder 9.1 makes Python return annotations complete HTTP response
contracts, from runtime validation through OpenAPI and generated clients.</p>
<section id="id2">
<h3>Added<a class="headerlink" href="#id2" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Return annotations are now complete response contracts. Any supported
Pydantic <code class="docutils literal notranslate"><span class="pre">TypeAdapter</span></code> shape — models, dataclasses, typed dictionaries,
collections such as <code class="docutils literal notranslate"><span class="pre">list[Item]</span></code>, unions, generic pagination models, and
JSON scalars — drives runtime validation and serialization, OpenAPI response
schemas, and generated-client types. Class-based-view method annotations and
Flask-style tuple annotations infer the same way. Inferred <code class="docutils literal notranslate"><span class="pre">str</span></code> and <code class="docutils literal notranslate"><span class="pre">bytes</span></code>
responses document and emit <code class="docutils literal notranslate"><span class="pre">text/plain</span></code> and <code class="docutils literal notranslate"><span class="pre">application/octet-stream</span></code>;
other inferred contracts use <code class="docutils literal notranslate"><span class="pre">application/json</span></code>.</p></li>
<li><p>Handlers may return <code class="docutils literal notranslate"><span class="pre">bool</span></code>, <code class="docutils literal notranslate"><span class="pre">int</span></code>, and <code class="docutils literal notranslate"><span class="pre">float</span></code> JSON scalars directly, in
addition to the existing dictionaries, lists, strings, bytes, models, and
dataclasses.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">responses={404:</span> <span class="pre">ErrorModel}</span></code> now declares a status-specific response
contract used for runtime validation and OpenAPI, including alternate
success statuses. A response mapping may provide <code class="docutils literal notranslate"><span class="pre">model</span></code> alongside a custom
description, headers, examples, or other OpenAPI metadata.</p></li>
</ul>
</section>
<section id="id3">
<h3>Changed<a class="headerlink" href="#id3" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Response contracts now validate the final success body after after-request
hooks. A body whose shape or response channel contradicts its declared model
fails closed with <code class="docutils literal notranslate"><span class="pre">500</span></code>, including a list returned for a single-object model;
<code class="docutils literal notranslate"><span class="pre">response_model=False</span></code> reliably disables inference and validation.</p></li>
<li><p>Flask-style return tuples now require exactly <code class="docutils literal notranslate"><span class="pre">(body,</span> <span class="pre">status)</span></code> or
<code class="docutils literal notranslate"><span class="pre">(body,</span> <span class="pre">status,</span> <span class="pre">headers)</span></code>, a status integer from 100 through 599, and a
header mapping. Malformed tuples fail clearly instead of being partially
applied or silently ignored.</p></li>
<li><p>Routes with unresolved or unsupported return annotations now log a focused
registration warning with the <code class="docutils literal notranslate"><span class="pre">response_model=False</span></code> opt-out instead of
silently dropping the inferred contract.</p></li>
</ul>
</section>
<section id="fixed">
<h3>Fixed<a class="headerlink" href="#fixed" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Informational, <code class="docutils literal notranslate"><span class="pre">204</span></code>, <code class="docutils literal notranslate"><span class="pre">205</span></code>, and <code class="docutils literal notranslate"><span class="pre">304</span></code> responses no longer send a body even
if a handler returned or assigned one. Their inferred OpenAPI success
responses omit content as well; <code class="docutils literal notranslate"><span class="pre">HEAD</span></code> continues to validate the
corresponding <code class="docutils literal notranslate"><span class="pre">GET</span></code> response while sending headers only.</p></li>
</ul>
</section>
</section>
<section id="v9-0-1-2026-07-06">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v9.0.0..v9.0.1">v9.0.1</a> - 2026-07-06<a class="headerlink" href="#v9-0-1-2026-07-06" title="Link to this heading"></a></h2>
<p>A bug-fix release from a post-9.0.0 adversarial scan: several v9-new
surfaces (CSRF, proxy headers, streaming form parsing, rate limiting,
GraphQL, OpenAPI caching) had crash or enforcement defects. Security-
relevant; upgrading from 9.0.0 is recommended.</p>
<section id="id4">
<h3>Fixed<a class="headerlink" href="#id4" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>CSRF: a non-ASCII submitted token (a fully client-controlled <code class="docutils literal notranslate"><span class="pre">csrf_token</span></code>
form field or <code class="docutils literal notranslate"><span class="pre">X-CSRF-Token</span></code> header) crashed <code class="docutils literal notranslate"><span class="pre">hmac.compare_digest</span></code> and
returned <code class="docutils literal notranslate"><span class="pre">500</span></code> instead of <code class="docutils literal notranslate"><span class="pre">403</span></code>; tokens are now compared as UTF-8 bytes.</p></li>
<li><p>CSRF: the per-route <code class="docutils literal notranslate"><span class="pre">csrf=</span></code> override was stored on the shared view object,
so re-registering a function with <code class="docutils literal notranslate"><span class="pre">csrf=False</span></code> stripped protection from its
earlier routes, and a CBV registered with <code class="docutils literal notranslate"><span class="pre">csrf=False</span></code> leaked the exemption
to subclasses through the MRO. Each registration’s value is now frozen onto
its own <code class="docutils literal notranslate"><span class="pre">Route</span></code>.</p></li>
<li><p>CSRF: <code class="docutils literal notranslate"><span class="pre">csrf=True</span></code> on a WebSocket route was accepted but never enforced; it
now raises at registration.</p></li>
<li><p>Proxy headers: a forwarded <code class="docutils literal notranslate"><span class="pre">Host</span></code> (or <code class="docutils literal notranslate"><span class="pre">Content-Length</span></code>) whose port/value is
a non-ASCII digit character (e.g. <code class="docutils literal notranslate"><span class="pre">U+00B2</span></code>, which <code class="docutils literal notranslate"><span class="pre">str.isdigit()</span></code> accepts
but <code class="docutils literal notranslate"><span class="pre">int()</span></code> rejects) raised an unhandled <code class="docutils literal notranslate"><span class="pre">ValueError</span></code>. In
<code class="docutils literal notranslate"><span class="pre">ProxyHeadersMiddleware</span></code> — the outermost layer — this sent no response at
all; both call sites now require <code class="docutils literal notranslate"><span class="pre">.isascii()</span></code> before <code class="docutils literal notranslate"><span class="pre">int()</span></code>.</p></li>
<li><p>Rate limiting: <code class="docutils literal notranslate"><span class="pre">&#64;limiter.limit</span></code> on a class-based-view method returned <code class="docutils literal notranslate"><span class="pre">500</span></code>
on every request because the wrapper mislocated the request/response past
the bound method’s <code class="docutils literal notranslate"><span class="pre">self</span></code>; they are now located by type.</p></li>
<li><p>GraphQL: a non-object JSON body (e.g. a JSON array) and a multipart POST
without a <code class="docutils literal notranslate"><span class="pre">query</span></code> field both returned <code class="docutils literal notranslate"><span class="pre">500</span></code>; both now return <code class="docutils literal notranslate"><span class="pre">400</span></code>.</p></li>
<li><p>Forms: a malformed or oversized multipart body on the buffered parse branch
raised an unhandled <code class="docutils literal notranslate"><span class="pre">500</span></code> instead of the documented <code class="docutils literal notranslate"><span class="pre">400</span></code>.</p></li>
<li><p>OpenAPI: the generated-document cache ignored <code class="docutils literal notranslate"><span class="pre">request_timeout</span></code> and
<code class="docutils literal notranslate"><span class="pre">problem_details</span></code>, so changing either after the first render served a stale
schema; both are now part of the cache key.</p></li>
</ul>
</section>
</section>
<section id="v9-0-0-2026-07-05">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v8.3.0..v9.0.0">v9.0.0</a> - 2026-07-05<a class="headerlink" href="#v9-0-0-2026-07-05" title="Link to this heading"></a></h2>
<p>A major release: streaming multipart uploads, opt-in CSRF protection,
reverse-proxy header support, and the v8.1 deprecation path becoming the
default behavior. See the
<a class="reference external" href="https://responder.kennethreitz.org/migration-v9.html">v9 migration guide</a>
for the full upgrade path.</p>
<section id="id5">
<h3>Added<a class="headerlink" href="#id5" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Opt-in CSRF protection: <code class="docutils literal notranslate"><span class="pre">API(csrf=True)</span></code> requires unsafe requests
(<code class="docutils literal notranslate"><span class="pre">POST</span></code>/<code class="docutils literal notranslate"><span class="pre">PUT</span></code>/<code class="docutils literal notranslate"><span class="pre">PATCH</span></code>/<code class="docutils literal notranslate"><span class="pre">DELETE</span></code>) to present the session-bound token from
<code class="docutils literal notranslate"><span class="pre">req.csrf_token</span></code> in an <code class="docutils literal notranslate"><span class="pre">X-CSRF-Token</span></code> header or <code class="docutils literal notranslate"><span class="pre">csrf_token</span></code> form field
(<code class="docutils literal notranslate"><span class="pre">{{</span> <span class="pre">req.csrf_input</span> <span class="pre">}}</span></code> renders the hidden input for templates), rejecting
the rest with a <code class="docutils literal notranslate"><span class="pre">403</span></code>. Per-route overrides via
<code class="docutils literal notranslate"><span class="pre">&#64;api.route(...,</span> <span class="pre">csrf=False)</span></code> (webhook receivers) or <code class="docutils literal notranslate"><span class="pre">csrf=True</span></code> (protect a
single route). The token check shares the request’s single streaming form
parse. Off by default; requires sessions.</p></li>
<li><p>Proxy-headers support: <code class="docutils literal notranslate"><span class="pre">API(trust_proxy_headers=True)</span></code> now installs a
middleware honoring RFC 7239 <code class="docutils literal notranslate"><span class="pre">Forwarded</span></code> and
<code class="docutils literal notranslate"><span class="pre">X-Forwarded-Proto</span></code>/<code class="docutils literal notranslate"><span class="pre">X-Forwarded-Host</span></code>/<code class="docutils literal notranslate"><span class="pre">X-Forwarded-For</span></code>/<code class="docutils literal notranslate"><span class="pre">X-Real-IP</span></code>,
rewriting the request’s scheme, host, and client address to what the
original client sent — HTTPS detection, redirects, URL building,
trusted-host validation, and logged client IPs are then correct behind
nginx/Caddy/load balancers.</p></li>
<li><p>Streaming multipart uploads: multipart bodies now parse incrementally off
the wire, spooling file parts to temporary files (rolling to disk past
~1 MB) instead of buffering the whole body in RAM. <code class="docutils literal notranslate"><span class="pre">File()</span></code> markers,
<code class="docutils literal notranslate"><span class="pre">req.media(&quot;files&quot;)</span></code>, and <code class="docutils literal notranslate"><span class="pre">req.media(&quot;form&quot;)</span></code> all share the single
streaming parse, and <code class="docutils literal notranslate"><span class="pre">max_request_size</span></code> is enforced chunk-by-chunk as the
body arrives — uploads are bounded by disk, not memory.</p></li>
</ul>
</section>
<section id="id6">
<h3>Changed<a class="headerlink" href="#id6" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">trust_proxy_headers=True</span></code> previously only affected the client IP recorded
by <code class="docutils literal notranslate"><span class="pre">enable_logging</span></code>; it now rewrites the connection’s scheme, host, and
client address for the whole stack (see Added). Apps that enabled it purely
for logging get the same logged IPs, plus correct scheme/host handling.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">max_request_size</span></code> now defaults to 100 MiB instead of unlimited; pass
<code class="docutils literal notranslate"><span class="pre">API(max_request_size=None)</span></code> for the previous behavior. Oversized bodies
get a <code class="docutils literal notranslate"><span class="pre">413</span></code> as before.</p></li>
<li><p>Generated OpenAPI operations now document Responder’s operational responses:
CSRF-protected unsafe routes get <code class="docutils literal notranslate"><span class="pre">403</span></code>, rate-limited routes get <code class="docutils literal notranslate"><span class="pre">429</span></code> (and
fail-closed backend <code class="docutils literal notranslate"><span class="pre">503</span></code>), and request-size <code class="docutils literal notranslate"><span class="pre">413</span></code> is emitted only when a
body cap is active. Rate limiter <code class="docutils literal notranslate"><span class="pre">429</span></code>/<code class="docutils literal notranslate"><span class="pre">503</span></code> responses now honor
<code class="docutils literal notranslate"><span class="pre">API(problem_details=True)</span></code> and keep the legacy <code class="docutils literal notranslate"><span class="pre">{&quot;error&quot;:</span> <span class="pre">...}</span></code> JSON shape
when <code class="docutils literal notranslate"><span class="pre">problem_details=False</span></code>.</p></li>
<li><p>Because multipart parsing streams, the raw body is consumed by the parse:
<code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">req.content</span></code> after <code class="docutils literal notranslate"><span class="pre">media(&quot;form&quot;/&quot;files&quot;)</span></code> raises a clear
<code class="docutils literal notranslate"><span class="pre">RuntimeError</span></code> (await <code class="docutils literal notranslate"><span class="pre">req.content</span></code> first to keep the buffered, replayable
8.x behavior), and handlers using <code class="docutils literal notranslate"><span class="pre">File()</span></code>/<code class="docutils literal notranslate"><span class="pre">Form()</span></code> markers no longer have
the raw multipart body available (matching Starlette/FastAPI). Multipart
text fields read via <code class="docutils literal notranslate"><span class="pre">media(&quot;form&quot;)</span></code> now share the streaming parser’s
limits (1000 parts, 1 MB per text field, <code class="docutils literal notranslate"><span class="pre">400</span></code> beyond them) and lossily
decode invalid UTF-8 instead of silently dropping the field.</p></li>
<li><p>Prepared the v9 behavior defaults: explicit <code class="docutils literal notranslate"><span class="pre">port=</span></code> now wins over a
conflicting <code class="docutils literal notranslate"><span class="pre">PORT</span></code> environment variable, bare <code class="docutils literal notranslate"><span class="pre">add_route()</span></code> calls require an
explicit endpoint by default, <code class="docutils literal notranslate"><span class="pre">Decimal</span></code> values serialize as strings by
default, and GraphQL partial-data responses default to HTTP <code class="docutils literal notranslate"><span class="pre">200</span></code>. The
explicit compatibility switches for these legacy behaviors remain available
without deprecation warnings while apps migrate.</p></li>
</ul>
</section>
<section id="removed">
<h3>Removed<a class="headerlink" href="#removed" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Removed the deprecated <code class="docutils literal notranslate"><span class="pre">API.session()</span></code> accessor. Use <code class="docutils literal notranslate"><span class="pre">api.requests</span></code> or
<code class="docutils literal notranslate"><span class="pre">api.test_client(...)</span></code> instead.</p></li>
</ul>
</section>
</section>
<section id="v8-3-0-2026-07-05">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v8.2.3..v8.3.0">v8.3.0</a> - 2026-07-05<a class="headerlink" href="#v8-3-0-2026-07-05" title="Link to this heading"></a></h2>
<section id="id7">
<h3>Added<a class="headerlink" href="#id7" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Added <code class="docutils literal notranslate"><span class="pre">api.test_client(...)</span></code>, a configurable form of <code class="docutils literal notranslate"><span class="pre">api.requests</span></code> for
custom <code class="docutils literal notranslate"><span class="pre">base_url</span></code> values and Starlette <code class="docutils literal notranslate"><span class="pre">TestClient</span></code> options such as
<code class="docutils literal notranslate"><span class="pre">raise_server_exceptions=False</span></code>, without relying on deprecated
<code class="docutils literal notranslate"><span class="pre">api.session()</span></code>.</p></li>
<li><p>Added v9 compatibility opt-ins: <code class="docutils literal notranslate"><span class="pre">API(json_decimal=&quot;string&quot;)</span></code> serializes
<code class="docutils literal notranslate"><span class="pre">Decimal</span></code> values as precision-preserving strings, and
<code class="docutils literal notranslate"><span class="pre">api.graphql(...,</span> <span class="pre">partial_data_status=200)</span></code> returns GraphQL partial-data
responses with HTTP <code class="docutils literal notranslate"><span class="pre">200</span></code> per the GraphQL-over-HTTP spec. Apps can also pass
<code class="docutils literal notranslate"><span class="pre">API(implicit_static_fallback=False)</span></code> to disable bare <code class="docutils literal notranslate"><span class="pre">add_route()</span></code> static
fallbacks early, and <code class="docutils literal notranslate"><span class="pre">port_precedence=&quot;explicit&quot;</span></code> to <code class="docutils literal notranslate"><span class="pre">serve()</span></code> / <code class="docutils literal notranslate"><span class="pre">run()</span></code> so
an explicit <code class="docutils literal notranslate"><span class="pre">port=</span></code> wins over a conflicting <code class="docutils literal notranslate"><span class="pre">PORT</span></code> environment variable.</p></li>
<li><p>Added <code class="docutils literal notranslate"><span class="pre">head()</span></code> and <code class="docutils literal notranslate"><span class="pre">options()</span></code> shortcut decorators on <code class="docutils literal notranslate"><span class="pre">API</span></code>, <code class="docutils literal notranslate"><span class="pre">RouteGroup</span></code>,
and standalone <code class="docutils literal notranslate"><span class="pre">Router</span></code> instances.</p></li>
</ul>
</section>
<section id="id8">
<h3>Changed<a class="headerlink" href="#id8" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Declared the Starlette test-client dependencies explicitly (<code class="docutils literal notranslate"><span class="pre">httpx</span></code> and
<code class="docutils literal notranslate"><span class="pre">httpx2</span></code>), raised the Uvicorn and Granian dependency floors to current
compatible releases, and allowed Sphinx 9 for documentation builds.</p></li>
<li><p>Removed the PyPy classifier and remaining PyPy-specific test-extra guidance
now that future CI runs target CPython only.</p></li>
</ul>
</section>
</section>
<section id="v8-2-3-2026-07-05">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v8.2.2..v8.2.3">v8.2.3</a> - 2026-07-05<a class="headerlink" href="#v8-2-3-2026-07-05" title="Link to this heading"></a></h2>
<section id="id9">
<h3>Fixed<a class="headerlink" href="#id9" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">RedisSessionBackend</span></code> and <code class="docutils literal notranslate"><span class="pre">AsyncRedisSessionBackend</span></code> now write sessions with
Redis <code class="docutils literal notranslate"><span class="pre">SET</span></code> plus expiry (<code class="docutils literal notranslate"><span class="pre">EX</span></code>) when the client supports it, avoiding the
<code class="docutils literal notranslate"><span class="pre">setex</span></code> deprecation warning emitted by current redis-py/fakeredis while
preserving a fallback for older or custom clients that only expose <code class="docutils literal notranslate"><span class="pre">setex</span></code>.</p></li>
</ul>
</section>
<section id="documentation">
<h3>Documentation<a class="headerlink" href="#documentation" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Added a runnable examples guide, surfaced it in the sidebar navigation, and
linked the existing v6 migration guide from the project navigation.</p></li>
<li><p>Updated the docs Makefile so <code class="docutils literal notranslate"><span class="pre">make</span> <span class="pre">html</span></code> uses the declared documentation
dependencies through <code class="docutils literal notranslate"><span class="pre">uv</span> <span class="pre">run</span> <span class="pre">--extra</span> <span class="pre">docs</span> <span class="pre">sphinx-build</span></code>.</p></li>
</ul>
</section>
</section>
<section id="v8-2-2-2026-07-03">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v8.2.1..v8.2.2">v8.2.2</a> - 2026-07-03<a class="headerlink" href="#v8-2-2-2026-07-03" title="Link to this heading"></a></h2>
<section id="id10">
<h3>Fixed<a class="headerlink" href="#id10" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">RateLimiter.limit</span></code> now propagates the decorated handler’s return value, so
return-value-style handlers (<code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre">{...}</span></code>, <code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre">text</span></code>, or
<code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre">data,</span> <span class="pre">status[,</span> <span class="pre">headers]</span></code>) compose with the decorator. Previously the
wrapper discarded the return value in both the sync and async branches, so
any <code class="docutils literal notranslate"><span class="pre">&#64;limiter.limit</span></code> handler that returned data instead of mutating <code class="docutils literal notranslate"><span class="pre">resp</span></code>
produced an empty <code class="docutils literal notranslate"><span class="pre">200</span></code> response. Mutation-style handlers were unaffected,
which is why it went unnoticed. The over-limit path is unchanged: a request
past the limit still gets a <code class="docutils literal notranslate"><span class="pre">429</span></code> with <code class="docutils literal notranslate"><span class="pre">Retry-After</span></code> and the handler is not
invoked.</p></li>
</ul>
</section>
</section>
<section id="v8-2-1-2026-07-03">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v8.2.0..v8.2.1">v8.2.1</a> - 2026-07-03<a class="headerlink" href="#v8-2-1-2026-07-03" title="Link to this heading"></a></h2>
<p>A security patch closing two response-injection gaps found by an adversarial
sweep over the non-auth framework surface (the auth extension was hardened in
8.2.0). Both fixes are defense-in-depth and change no legitimate behavior.</p>
<section id="security">
<h3>Security<a class="headerlink" href="#security" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Response header values are now stripped of CR, LF, and NUL before they reach
the ASGI layer, closing an HTTP response-splitting / header-injection vector.
A user-controlled value written to a header — most commonly a redirect target
via <code class="docutils literal notranslate"><span class="pre">Response.redirect(location)</span></code> or <code class="docutils literal notranslate"><span class="pre">Response.created(location=...)</span></code>, but also
any <code class="docutils literal notranslate"><span class="pre">resp.headers[...]</span> <span class="pre">=</span> <span class="pre">...</span></code> assignment — could previously carry a bare
<code class="docutils literal notranslate"><span class="pre">\r\n</span></code> onto the wire, letting an attacker inject additional response headers
(e.g. <code class="docutils literal notranslate"><span class="pre">Set-Cookie</span></code>) or split the response on ASGI servers/proxies that don’t
reject embedded control bytes. The framework already scrubbed CR/LF from
<code class="docutils literal notranslate"><span class="pre">Content-Disposition</span></code> and Server-Sent Events fields; this extends the same
discipline to every response header.</p></li>
<li><p>The access-log middleware (<code class="docutils literal notranslate"><span class="pre">responder.ext.logging</span></code>) now strips control
characters (C0 range and DEL) from the request method and path before logging
them. Because ASGI servers percent-decode <code class="docutils literal notranslate"><span class="pre">scope[&quot;path&quot;]</span></code>, a request to a
path like <code class="docutils literal notranslate"><span class="pre">/x%0d%0a[INFO]...</span></code> previously wrote a raw CR/LF into the log line,
letting an attacker forge log records in a plaintext log sink. Spaces and
non-ASCII in a decoded path are preserved — only control bytes are removed —
mirroring the validation already applied to inbound <code class="docutils literal notranslate"><span class="pre">X-Request-ID</span></code>.</p></li>
</ul>
</section>
</section>
<section id="v8-2-0-2026-07-03">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v8.1.0..v8.2.0">v8.2.0</a> - 2026-07-03<a class="headerlink" href="#v8-2-0-2026-07-03" title="Link to this heading"></a></h2>
<p>A security-focused release hardening the JWT/OAuth2 authentication introduced
in 8.1.0. A dedicated adversarial pass over the new auth code surfaced nine
issues (all in <code class="docutils literal notranslate"><span class="pre">responder.ext.auth</span></code>); every fix ships with a regression test.</p>
<section id="id11">
<h3>Security<a class="headerlink" href="#id11" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">JWTAuth</span></code> rejects a plaintext (<code class="docutils literal notranslate"><span class="pre">http</span></code>) <code class="docutils literal notranslate"><span class="pre">jwks_url</span></code> at construction unless it
targets loopback (<code class="docutils literal notranslate"><span class="pre">localhost</span></code>/<code class="docutils literal notranslate"><span class="pre">127.0.0.1</span></code>/<code class="docutils literal notranslate"><span class="pre">[::1]</span></code>) or <code class="docutils literal notranslate"><span class="pre">allow_insecure_jwks=True</span></code>
is passed. A man-in-the-middle on a plaintext JWKS fetch could serve
attacker-controlled signing keys — a full authentication bypass.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">JWTAuth</span></code> no longer lets an attacker-controlled, unknown <code class="docutils literal notranslate"><span class="pre">kid</span></code> amplify into
unbounded blocking JWKS refetches. The JWKS client now caches keys, and a
missing <code class="docutils literal notranslate"><span class="pre">kid</span></code> triggers at most one network refresh per short cooldown window
(otherwise rejecting with <code class="docutils literal notranslate"><span class="pre">401</span></code> and no fetch), closing an unauthenticated
denial-of-service vector. The JWKS cache is lock-guarded for the threadpool.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">JWTAuth</span></code> rejects tokens without an <code class="docutils literal notranslate"><span class="pre">exp</span></code> claim by default (new
<code class="docutils literal notranslate"><span class="pre">require_exp=True</span></code>); previously an expiry-less token was accepted
indefinitely. See the note under Changed to restore the old behavior.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">OAuth2Auth</span></code> no longer mutates token-introspection principals in place, and a
previously-stamped <code class="docutils literal notranslate"><span class="pre">scopes</span></code> value no longer short-circuits a fresh
introspection result — fixing privilege retention where a token that the
authorization server had downscoped kept its old, broader scopes.</p></li>
</ul>
</section>
<section id="id12">
<h3>Changed<a class="headerlink" href="#id12" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">JWTAuth(require_exp=...)</span></code> defaults to <code class="docutils literal notranslate"><span class="pre">True</span></code>, so tokens without an <code class="docutils literal notranslate"><span class="pre">exp</span></code>
claim are rejected. This is stricter than 8.1.0, which accepted them. If you
intentionally issue non-expiring JWTs, pass <code class="docutils literal notranslate"><span class="pre">require_exp=False</span></code>.</p></li>
</ul>
</section>
<section id="id13">
<h3>Fixed<a class="headerlink" href="#id13" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">JWTAuth</span></code>: a JWKS-configured scheme no longer raises an uncaught <code class="docutils literal notranslate"><span class="pre">TypeError</span></code>
(HTTP 500) when sent an <code class="docutils literal notranslate"><span class="pre">HS256</span></code> token whose <code class="docutils literal notranslate"><span class="pre">kid</span></code> resolves to a public key —
the mismatch now rejects with <code class="docutils literal notranslate"><span class="pre">401</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">JWTAuth</span></code>: <code class="docutils literal notranslate"><span class="pre">audience=None</span></code> now actually disables <code class="docutils literal notranslate"><span class="pre">aud</span></code> verification, so tokens
carrying an <code class="docutils literal notranslate"><span class="pre">aud</span></code> claim (virtually every OIDC access token) are accepted
instead of being rejected with <code class="docutils literal notranslate"><span class="pre">401</span></code>. When <code class="docutils literal notranslate"><span class="pre">audience</span></code> is set, it is still
enforced.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">JWTAuth</span></code>/<code class="docutils literal notranslate"><span class="pre">OAuth2Auth</span></code>: the <code class="docutils literal notranslate"><span class="pre">scope</span></code> and <code class="docutils literal notranslate"><span class="pre">scp</span></code> claims are now unioned rather
than the first-present one winning, so an Azure AD / Auth0 token that carries
its granted scopes in <code class="docutils literal notranslate"><span class="pre">scp</span></code> (with an empty <code class="docutils literal notranslate"><span class="pre">scope</span></code>) is no longer denied <code class="docutils literal notranslate"><span class="pre">403</span></code>.</p></li>
<li><p>OAuth2 flows: constructing a flow with an empty required URL
(<code class="docutils literal notranslate"><span class="pre">authorizationUrl</span></code>/<code class="docutils literal notranslate"><span class="pre">tokenUrl</span></code>) now raises <code class="docutils literal notranslate"><span class="pre">ValueError</span></code> instead of silently
emitting an OpenAPI security scheme that fails validation.</p></li>
</ul>
</section>
<section id="packaging">
<h3>Packaging<a class="headerlink" href="#packaging" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>The <code class="docutils literal notranslate"><span class="pre">orjson</span></code> and <code class="docutils literal notranslate"><span class="pre">fakeredis[lua]</span></code> test dependencies (compiled, without wheels
on free-threaded CPython or PyPy) moved out of the <code class="docutils literal notranslate"><span class="pre">test</span></code> extra into a
version-scoped CI step, so <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">responder[test]</span></code> on free-threaded
3.14 no longer fails trying to build them from source.</p></li>
</ul>
</section>
</section>
<section id="v8-1-0-2026-07-03">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v8.0.2..v8.1.0">v8.1.0</a> - 2026-07-03<a class="headerlink" href="#v8-1-0-2026-07-03" title="Link to this heading"></a></h2>
<section id="id14">
<h3>Added<a class="headerlink" href="#id14" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">JWTAuth</span></code> in <code class="docutils literal notranslate"><span class="pre">responder.ext.auth</span></code>: <code class="docutils literal notranslate"><span class="pre">Authorization:</span> <span class="pre">Bearer</span></code> authentication
with full JWT validation — signature (HS256 by default; RS256/ES256 and
friends when <code class="docutils literal notranslate"><span class="pre">cryptography</span></code> is installed), <code class="docutils literal notranslate"><span class="pre">exp</span></code>/<code class="docutils literal notranslate"><span class="pre">nbf</span></code>/<code class="docutils literal notranslate"><span class="pre">iat</span></code> with a
configurable <code class="docutils literal notranslate"><span class="pre">leeway</span></code>, and <code class="docutils literal notranslate"><span class="pre">audience</span></code>/<code class="docutils literal notranslate"><span class="pre">issuer</span></code> checks. Keys come from a
static <code class="docutils literal notranslate"><span class="pre">secret</span></code> (HMAC secret or PEM public key) or a <code class="docutils literal notranslate"><span class="pre">jwks_url</span></code>, resolved by
the token’s <code class="docutils literal notranslate"><span class="pre">kid</span></code> header with cached key sets that refresh automatically on
rotation (the JWKS fetch runs off the event loop). The validated claims
become the injected principal — or pass <code class="docutils literal notranslate"><span class="pre">verify=</span></code> to map them onto your own
user object — and the token’s <code class="docutils literal notranslate"><span class="pre">scope</span></code>/<code class="docutils literal notranslate"><span class="pre">scp</span></code> claim is normalized into the
scopes that feed <code class="docutils literal notranslate"><span class="pre">requires()</span></code>. Invalid tokens reject with <code class="docutils literal notranslate"><span class="pre">401</span></code> + a <code class="docutils literal notranslate"><span class="pre">Bearer</span></code>
challenge, missing scopes with <code class="docutils literal notranslate"><span class="pre">403</span></code> + <code class="docutils literal notranslate"><span class="pre">insufficient_scope</span></code>. Requires the new
<code class="docutils literal notranslate"><span class="pre">responder[jwt]</span></code> extra (PyJWT), imported lazily with a helpful error.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">OAuth2Auth</span></code> and flow descriptions (<code class="docutils literal notranslate"><span class="pre">OAuth2AuthorizationCodeFlow</span></code>,
<code class="docutils literal notranslate"><span class="pre">OAuth2ClientCredentialsFlow</span></code>, <code class="docutils literal notranslate"><span class="pre">OAuth2PasswordFlow</span></code>) in <code class="docutils literal notranslate"><span class="pre">responder.ext.auth</span></code>:
the OpenAPI document emits a proper <code class="docutils literal notranslate"><span class="pre">type:</span> <span class="pre">oauth2</span></code> security scheme with flows
and scopes, lighting up Swagger UI’s Authorize button. At runtime it acts as
a resource server — bearer tokens are validated locally through a <code class="docutils literal notranslate"><span class="pre">jwt=</span></code>
<code class="docutils literal notranslate"><span class="pre">JWTAuth</span></code> or a <code class="docutils literal notranslate"><span class="pre">verify=</span></code> token-introspection callable. Convenience
constructors <code class="docutils literal notranslate"><span class="pre">OAuth2Auth.authorization_code(...)</span></code>, <code class="docutils literal notranslate"><span class="pre">.client_credentials(...)</span></code>,
and <code class="docutils literal notranslate"><span class="pre">.password(...)</span></code> cover the single-flow cases; both compose with
<code class="docutils literal notranslate"><span class="pre">requires()</span></code>/<code class="docutils literal notranslate"><span class="pre">optional()</span></code>/<code class="docutils literal notranslate"><span class="pre">AuthPolicy</span></code> and group-level auth via
<code class="docutils literal notranslate"><span class="pre">Router</span></code>/<code class="docutils literal notranslate"><span class="pre">include_router</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">responder.Problem</span></code> — a raisable RFC 9457 problem-details exception. Raise
<code class="docutils literal notranslate"><span class="pre">Problem(409,</span> <span class="pre">&quot;detail&quot;,</span> <span class="pre">title=...,</span> <span class="pre">type=...,</span> <span class="pre">instance=...,</span> <span class="pre">**extensions)</span></code>
from any view, hook, or dependency to short-circuit with a full
<code class="docutils literal notranslate"><span class="pre">application/problem+json</span></code> response, rendered through the same pipeline as
framework errors (<code class="docutils literal notranslate"><span class="pre">problem_handler</span></code> enrichment, request IDs, the app’s JSON
encoder). <code class="docutils literal notranslate"><span class="pre">instance</span></code> defaults to the request path, and because it subclasses
Starlette’s <code class="docutils literal notranslate"><span class="pre">HTTPException</span></code>, existing handlers and middleware treat it like
<code class="docutils literal notranslate"><span class="pre">abort()</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">abort()</span></code> now accepts the RFC 9457 members — <code class="docutils literal notranslate"><span class="pre">title=</span></code>, <code class="docutils literal notranslate"><span class="pre">type=</span></code>, <code class="docutils literal notranslate"><span class="pre">instance=</span></code>,
<code class="docutils literal notranslate"><span class="pre">errors=</span></code>, and arbitrary extension keywords — raising a <code class="docutils literal notranslate"><span class="pre">Problem</span></code> that
carries them into the payload. Plain <code class="docutils literal notranslate"><span class="pre">abort(status,</span> <span class="pre">detail=...,</span> <span class="pre">headers=...)</span></code>
still raises a regular <code class="docutils literal notranslate"><span class="pre">HTTPException</span></code>, unchanged.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">&#64;api.middleware(&quot;http&quot;)</span></code> — a decorator for function-style HTTP middleware:
<code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span> <span class="pre">mw(request,</span> <span class="pre">call_next)</span> <span class="pre">-&gt;</span> <span class="pre">response</span></code>, no ASGI class boilerplate.
Synchronous functions run on a dedicated thread pool and receive a blocking
<code class="docutils literal notranslate"><span class="pre">call_next</span></code>. Function middleware registers through the same stack as
<code class="docutils literal notranslate"><span class="pre">add_middleware</span></code>, so the two compose: the most-recently-registered user
middleware is outermost. Backed by the new public
<code class="docutils literal notranslate"><span class="pre">responder.middleware.FunctionMiddleware</span></code> adapter; WebSocket and lifespan
traffic pass through untouched.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">req.headers.get_list(&quot;X-Forwarded-For&quot;)</span></code> returns every raw line of a
repeated request header, in the order received — duplicate header lines are
no longer silently collapsed. Single-value access is unchanged: last wins.</p></li>
<li><p>Write-side HTTP preconditions (RFC 9110 §13): on state-changing methods,
when <code class="docutils literal notranslate"><span class="pre">resp.etag</span></code> or <code class="docutils literal notranslate"><span class="pre">resp.last_modified</span></code> is set, <code class="docutils literal notranslate"><span class="pre">If-Match</span></code> (strong
comparison, <code class="docutils literal notranslate"><span class="pre">*</span></code> supported), <code class="docutils literal notranslate"><span class="pre">If-Unmodified-Since</span></code> (only when <code class="docutils literal notranslate"><span class="pre">If-Match</span></code> is
absent), and <code class="docutils literal notranslate"><span class="pre">If-None-Match</span></code> are evaluated, and a failing precondition
answers <code class="docutils literal notranslate"><span class="pre">412</span> <span class="pre">Precondition</span> <span class="pre">Failed</span></code>. Repeated header lines are folded per the
RFC. Like the existing <code class="docutils literal notranslate"><span class="pre">304</span></code> handling, preconditions are checked only when
the matching validator is set.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">req.preferred_media_type(candidates)</span></code> — ranks candidate media types (or
bare subtype tokens) by the q-value of the most specific matching <code class="docutils literal notranslate"><span class="pre">Accept</span></code>
range and returns the client’s preferred one, or <code class="docutils literal notranslate"><span class="pre">None</span></code> when it accepts
none. Ties, and requests without an <code class="docutils literal notranslate"><span class="pre">Accept</span></code> header, keep the candidate
order.</p></li>
<li><p>Pydantic body-model injection for class-based views:
<code class="docutils literal notranslate"><span class="pre">on_post(self,</span> <span class="pre">req,</span> <span class="pre">resp,</span> <span class="pre">*,</span> <span class="pre">item:</span> <span class="pre">Item)</span></code> receives the parsed, validated
body exactly like function views (automatic <code class="docutils literal notranslate"><span class="pre">422</span></code> on invalid input). The
body is parsed once per request, so <code class="docutils literal notranslate"><span class="pre">on_request</span></code> and a method handler
declaring the same model share one validated instance.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Query()</span></code>, <code class="docutils literal notranslate"><span class="pre">Header()</span></code>, <code class="docutils literal notranslate"><span class="pre">Cookie()</span></code>, and <code class="docutils literal notranslate"><span class="pre">Path()</span></code> markers now resolve on
WebSocket handlers from the handshake request (query string, headers,
cookies), with the same Pydantic coercion as HTTP views. A missing required
value or failed coercion closes the socket with <code class="docutils literal notranslate"><span class="pre">1008</span></code> (policy violation)
before the handler runs.</p></li>
<li><p>Bind an entire form to a Pydantic model: a parameter annotated with a
<code class="docutils literal notranslate"><span class="pre">BaseModel</span></code> subclass and a <code class="docutils literal notranslate"><span class="pre">Form(...)</span></code> default validates the parsed
urlencoded/multipart form into the model in one shot — repeated keys collect
into list fields, uploads bind to <code class="docutils literal notranslate"><span class="pre">UploadFile</span></code> fields, aliases are honored,
and failures return the same <code class="docutils literal notranslate"><span class="pre">422</span></code> payload as JSON body models with
<code class="docutils literal notranslate"><span class="pre">[&quot;form&quot;,</span> <span class="pre">&lt;field&gt;]</span></code> error locations. The OpenAPI schema documents the model
as the <code class="docutils literal notranslate"><span class="pre">multipart/form-data</span></code>/<code class="docutils literal notranslate"><span class="pre">application/x-www-form-urlencoded</span></code> requestBody.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">RateLimiter</span></code> accepts <code class="docutils literal notranslate"><span class="pre">key=</span></code> — a callable <code class="docutils literal notranslate"><span class="pre">req</span> <span class="pre">-&gt;</span> <span class="pre">str</span></code> naming the bucket a
request counts against (an API key, a user id) instead of the client IP
(still the default and the fallback) — and <code class="docutils literal notranslate"><span class="pre">fail_open=</span></code>: when the backend
errors out (e.g. Redis is unreachable), <code class="docutils literal notranslate"><span class="pre">fail_open=True</span></code> logs a warning and
lets the request through, while the default <code class="docutils literal notranslate"><span class="pre">False</span></code> answers <code class="docutils literal notranslate"><span class="pre">503</span></code> instead of
an unhandled 500. Every response now carries <code class="docutils literal notranslate"><span class="pre">X-RateLimit-Reset</span></code>; the backend
<code class="docutils literal notranslate"><span class="pre">hit()</span></code>/<code class="docutils literal notranslate"><span class="pre">ahit()</span></code> contract grew a third <code class="docutils literal notranslate"><span class="pre">reset_after</span></code> element, with 2-tuple
third-party backends still accepted (the header is omitted).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">MetricsCollector</span></code> accepts <code class="docutils literal notranslate"><span class="pre">buckets=</span></code> — ascending histogram bucket bounds —
exposed as <code class="docutils literal notranslate"><span class="pre">API(metrics_buckets=...)</span></code>, and <code class="docutils literal notranslate"><span class="pre">/metrics</span></code> now exports a
<code class="docutils literal notranslate"><span class="pre">responder_requests_in_flight</span></code> gauge.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">responder.ext.pagination.set_pagination_headers(req,</span> <span class="pre">resp,</span> <span class="pre">page)</span></code> emits the
RFC 8288 <code class="docutils literal notranslate"><span class="pre">Link</span></code> header (<code class="docutils literal notranslate"><span class="pre">rel=&quot;first&quot;</span></code>/<code class="docutils literal notranslate"><span class="pre">&quot;prev&quot;</span></code>/<code class="docutils literal notranslate"><span class="pre">&quot;next&quot;</span></code>/<code class="docutils literal notranslate"><span class="pre">&quot;last&quot;</span></code>, built from
the request URL with all other query parameters preserved) plus
<code class="docutils literal notranslate"><span class="pre">X-Total-Count</span></code>, alongside the existing <code class="docutils literal notranslate"><span class="pre">Page</span></code> body envelope.</p></li>
<li><p>CLI: <code class="docutils literal notranslate"><span class="pre">responder</span> <span class="pre">run</span></code> accepts <code class="docutils literal notranslate"><span class="pre">--host=&lt;addr&gt;</span></code>, <code class="docutils literal notranslate"><span class="pre">--port=&lt;n&gt;</span></code>, and
<code class="docutils literal notranslate"><span class="pre">--server=&lt;name&gt;</span></code> (<code class="docutils literal notranslate"><span class="pre">uvicorn</span></code> or <code class="docutils literal notranslate"><span class="pre">granian</span></code>) to control binding and backend,
plus <code class="docutils literal notranslate"><span class="pre">--reload</span></code> for uvicorn auto-reload (requires a <code class="docutils literal notranslate"><span class="pre">module:attr</span></code> target).</p></li>
<li><p>Optional orjson JSON backend: when orjson is installed
(<code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">&quot;responder[orjson]&quot;</span></code>), JSON responses encode via orjson —
typically several times faster, with less event-loop blocking. Custom
<code class="docutils literal notranslate"><span class="pre">API(encoder=...)</span></code> hooks keep working, and <code class="docutils literal notranslate"><span class="pre">json_ensure_ascii=True</span></code> stays on
the stdlib (orjson is UTF-8-only). Decoding continues to use the stdlib so
arbitrary-precision integers stay exact. Encoded output differs only in
whitespace, except float <code class="docutils literal notranslate"><span class="pre">nan</span></code>/<code class="docutils literal notranslate"><span class="pre">inf</span></code> serialize as <code class="docutils literal notranslate"><span class="pre">null</span></code> instead of the
non-standard <code class="docutils literal notranslate"><span class="pre">NaN</span></code>/<code class="docutils literal notranslate"><span class="pre">Infinity</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">responder.testing.AsyncTestClient</span></code>: the async mirror of <code class="docutils literal notranslate"><span class="pre">api.requests</span></code> — an
<code class="docutils literal notranslate"><span class="pre">httpx.AsyncClient</span></code> dispatching in-process; <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">with</span></code> runs the app’s
lifespan. Backed by <code class="docutils literal notranslate"><span class="pre">ASGIStreamingTransport</span></code>, which streams response bodies
live, so endless SSE streams can be read and closed mid-flight.</p></li>
<li><p>SSE test helpers in <code class="docutils literal notranslate"><span class="pre">responder.testing</span></code>: <code class="docutils literal notranslate"><span class="pre">parse_sse(text)</span></code>,
<code class="docutils literal notranslate"><span class="pre">iter_sse(response)</span></code>, and <code class="docutils literal notranslate"><span class="pre">collect_sse(response)</span></code> parse <code class="docutils literal notranslate"><span class="pre">text/event-stream</span></code>
bodies into <code class="docutils literal notranslate"><span class="pre">SSEEvent</span></code> objects (<code class="docutils literal notranslate"><span class="pre">data</span></code>/<code class="docutils literal notranslate"><span class="pre">event</span></code>/<code class="docutils literal notranslate"><span class="pre">id</span></code>/<code class="docutils literal notranslate"><span class="pre">retry</span></code>, plus <code class="docutils literal notranslate"><span class="pre">.json()</span></code>),
skipping heartbeat comments — the client-side mirror of <code class="docutils literal notranslate"><span class="pre">resp.sse</span></code>.</p></li>
<li><p>Test coverage for the Redis session and rate-limit backends against
<code class="docutils literal notranslate"><span class="pre">fakeredis</span></code> (sync and async, including the atomic INCR+EXPIRE Lua script),
covering TTL/expiry, key prefixes, middleware round-trips, and outage
behavior.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">status_code=</span></code> route option: <code class="docutils literal notranslate"><span class="pre">&#64;api.route(&quot;/items&quot;,</span> <span class="pre">methods=[&quot;POST&quot;],</span> <span class="pre">status_code=201)</span></code> pre-seeds <code class="docutils literal notranslate"><span class="pre">resp.status_code</span></code> (an explicit assignment in
the view still wins) and documents the success response under that status in
the OpenAPI operation instead of a hardcoded <code class="docutils literal notranslate"><span class="pre">200</span></code>. Works with the method
sugar, <code class="docutils literal notranslate"><span class="pre">api.group()</span></code>, and standalone <code class="docutils literal notranslate"><span class="pre">responder.Router</span></code> declarations.</p></li>
</ul>
</section>
<section id="id15">
<h3>Changed<a class="headerlink" href="#id15" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Content negotiation honors the client’s q-ranked <code class="docutils literal notranslate"><span class="pre">Accept</span></code> preference order
when a response could serialize to multiple registered formats, instead of
always serving the first registered format:
<code class="docutils literal notranslate"><span class="pre">Accept:</span> <span class="pre">application/yaml;q=0.9,</span> <span class="pre">application/json;q=0.1</span></code> now gets YAML where
it previously got JSON. Behavior changes only when a client explicitly ranks
formats — spec-correct per RFC 9110 §12.5.1; without an <code class="docutils literal notranslate"><span class="pre">Accept</span></code> header (or
when everything ties) JSON remains the default.</p></li>
<li><p>Class-based views now auto-answer <code class="docutils literal notranslate"><span class="pre">OPTIONS</span></code>. A CBV that defines neither
<code class="docutils literal notranslate"><span class="pre">on_options</span></code> nor <code class="docutils literal notranslate"><span class="pre">on_request</span></code> responds to <code class="docutils literal notranslate"><span class="pre">OPTIONS</span></code> with <code class="docutils literal notranslate"><span class="pre">200</span></code> and an
<code class="docutils literal notranslate"><span class="pre">Allow</span></code> header listing the methods it serves, instead of <code class="docutils literal notranslate"><span class="pre">405</span></code> — the same
treatment method-restricted function routes already got (RFC 9110 §9.3.7).
The <code class="docutils literal notranslate"><span class="pre">Allow</span></code> header on a CBV’s <code class="docutils literal notranslate"><span class="pre">405</span></code> response now includes <code class="docutils literal notranslate"><span class="pre">OPTIONS</span></code> too,
keeping the advertised methods consistent between the two paths.</p></li>
<li><p>Class-based views now reject unsupported HTTP methods with <code class="docutils literal notranslate"><span class="pre">405</span></code> <em>before</em>
validating typed parameters, so a request using a method the CBV does not
serve gets <code class="docutils literal notranslate"><span class="pre">405</span></code> (with <code class="docutils literal notranslate"><span class="pre">Allow</span></code>) rather than a <code class="docutils literal notranslate"><span class="pre">422</span></code> from a handler that would
never run — matching how function routes have always ordered method dispatch
and parameter validation. Supported methods still validate and return <code class="docutils literal notranslate"><span class="pre">422</span></code>
on bad input.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">RequestIDMiddleware</span></code> and <code class="docutils literal notranslate"><span class="pre">LoggingMiddleware</span></code> now share one request-ID
policy: an inbound <code class="docutils literal notranslate"><span class="pre">X-Request-ID</span></code> is honored when it is at most 128 printable
ASCII characters (<code class="docutils literal notranslate"><span class="pre">\x21</span></code>–<code class="docutils literal notranslate"><span class="pre">\x7e</span></code>, so namespaced ids like <code class="docutils literal notranslate"><span class="pre">gateway:abc123</span></code> and
base64-flavored ids pass, while control characters and oversized values are
replaced to prevent header/log injection and bloat), and both mint full
UUID4s
otherwise — <code class="docutils literal notranslate"><span class="pre">LoggingMiddleware</span></code> previously minted 8-hex-char ids (32 bits of
entropy), so a busy fleet risked collisions and flipping <code class="docutils literal notranslate"><span class="pre">enable_logging</span></code>
changed the ID format. <code class="docutils literal notranslate"><span class="pre">setup_logging</span></code> is now exported in <code class="docutils literal notranslate"><span class="pre">__all__</span></code>.</p></li>
<li><p>Coverage is now enforced (<code class="docutils literal notranslate"><span class="pre">fail_under</span> <span class="pre">=</span> <span class="pre">80</span></code>, previously 0) and measures only
the <code class="docutils literal notranslate"><span class="pre">responder</span></code> package, so generated clientgen artifacts and <code class="docutils literal notranslate"><span class="pre">examples/*.py</span></code>
no longer pollute the report.</p></li>
<li><p>The generated OpenAPI document is cached instead of rebuilt on every request
to the schema route or docs page; registering a route, schema, or security
scheme invalidates the cache.</p></li>
</ul>
</section>
<section id="id16">
<h3>Fixed<a class="headerlink" href="#id16" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Session values that work with <code class="docutils literal notranslate"><span class="pre">MemorySessionBackend</span></code> — <code class="docutils literal notranslate"><span class="pre">datetime</span></code>, <code class="docutils literal notranslate"><span class="pre">date</span></code>,
<code class="docutils literal notranslate"><span class="pre">time</span></code>, <code class="docutils literal notranslate"><span class="pre">Decimal</span></code>, <code class="docutils literal notranslate"><span class="pre">UUID</span></code>, <code class="docutils literal notranslate"><span class="pre">set</span></code>, <code class="docutils literal notranslate"><span class="pre">frozenset</span></code>, <code class="docutils literal notranslate"><span class="pre">bytes</span></code> — no longer crash the
Redis session backends with a hard-to-debug 500: the new default
<code class="docutils literal notranslate"><span class="pre">JSONSessionSerializer</span></code> round-trips those types (and refuses user data that
collides with its reserved type tag), and a <code class="docutils literal notranslate"><span class="pre">serializer=</span></code> parameter accepts
any custom <code class="docutils literal notranslate"><span class="pre">dumps</span></code>/<code class="docutils literal notranslate"><span class="pre">loads</span></code> codec. The storable-values contract is documented
for all backends.</p></li>
<li><p>Prometheus <code class="docutils literal notranslate"><span class="pre">/metrics</span></code> output escapes backslashes, double quotes, and
newlines in label values per the exposition format, so a route pattern
containing them can no longer break the whole scrape. The <code class="docutils literal notranslate"><span class="pre">RateLimiter</span></code>
docstring no longer claims “token bucket” (the memory backend is a sliding
window; the Redis backends are fixed-window).</p></li>
<li><p>Registering two <em>different</em> security schemes under the same name now raises
instead of silently overwriting (idempotent re-registration of the same
scheme, which routing performs per route, is still fine).</p></li>
<li><p>CLI: bare <code class="docutils literal notranslate"><span class="pre">responder</span></code> with no subcommand prints the usage summary and exits
non-zero instead of silently exiting <code class="docutils literal notranslate"><span class="pre">0</span></code>.</p></li>
</ul>
</section>
<section id="deprecated">
<h3>Deprecated<a class="headerlink" href="#deprecated" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">API.session()</span></code> — use the <code class="docutils literal notranslate"><span class="pre">api.requests</span></code> property. Emits a
<code class="docutils literal notranslate"><span class="pre">DeprecationWarning</span></code>; removal in 9.0.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">PORT</span></code> environment variable overriding an explicitly passed <code class="docutils literal notranslate"><span class="pre">port=</span></code> in
<code class="docutils literal notranslate"><span class="pre">serve()</span></code>/<code class="docutils literal notranslate"><span class="pre">run()</span></code>. Warns only when both are set and differ; the environment
variable still wins until 9.0, when explicit <code class="docutils literal notranslate"><span class="pre">port=</span></code> will take precedence.</p></li>
<li><p>Calling <code class="docutils literal notranslate"><span class="pre">add_route()</span></code> without an endpoint (implicitly registering a
static-fallback route). Pass an endpoint explicitly (with <code class="docutils literal notranslate"><span class="pre">default=True</span></code> for
a catch-all); the implicit behavior is removed in 9.0.</p></li>
<li><p>Lossy <code class="docutils literal notranslate"><span class="pre">decimal.Decimal</span></code>-to-float JSON serialization. Warns once per process
when a bare <code class="docutils literal notranslate"><span class="pre">Decimal</span></code> reaches the built-in encoder; 9.0 will serialize
<code class="docutils literal notranslate"><span class="pre">Decimal</span></code> as strings. Convert explicitly or pass a custom <code class="docutils literal notranslate"><span class="pre">encoder=</span></code>.</p></li>
<li><p>GraphQL responses returning HTTP 400 when the result contains partial data
alongside errors. Warns once per process; 9.0 will return 200 for such
responses per the GraphQL-over-HTTP spec (no-data error responses keep 400).</p></li>
</ul>
</section>
</section>
<section id="v8-0-2-2026-07-03">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v8.0.1..v8.0.2">v8.0.2</a> - 2026-07-03<a class="headerlink" href="#v8-0-2-2026-07-03" title="Link to this heading"></a></h2>
<section id="id17">
<h3>Fixed<a class="headerlink" href="#id17" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">ResponderServer</span></code>’s private process-termination method no longer shadows
<code class="docutils literal notranslate"><span class="pre">threading.Thread._stop()</span></code>. On Python ≤ 3.12 and PyPy, <code class="docutils literal notranslate"><span class="pre">Thread.join()</span></code> calls
<code class="docutils literal notranslate"><span class="pre">self._stop()</span></code> internally, so joining a <code class="docutils literal notranslate"><span class="pre">ResponderServer</span></code> invoked the
process-termination logic (marking the server as stopping and skipping the
Thread’s own bookkeeping) instead of just waiting. Python 3.13+ was
unaffected. Latent since the class was introduced; surfaced by the 8.0.1
signal-handler restore tests.</p></li>
</ul>
</section>
</section>
<section id="v8-0-1-2026-07-02">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v8.0.0..v8.0.1">v8.0.1</a> - 2026-07-02<a class="headerlink" href="#v8-0-1-2026-07-02" title="Link to this heading"></a></h2>
<section id="id18">
<h3>Added<a class="headerlink" href="#id18" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>A “Migrating to v8” guide in the documentation, covering every 8.0 breaking
change with before/after examples — implicit <code class="docutils literal notranslate"><span class="pre">static/</span></code> removal,
<code class="docutils literal notranslate"><span class="pre">RouteNotFoundError</span></code> and percent-encoding in <code class="docutils literal notranslate"><span class="pre">url_for</span></code>, the 307 redirect
default, text-response charsets, <code class="docutils literal notranslate"><span class="pre">application/yaml</span></code>, empty-YAML-body 400s,
and the new dependency declarations and floors — plus a pointer to the
standalone-routers guide.</p></li>
</ul>
</section>
<section id="id19">
<h3>Fixed<a class="headerlink" href="#id19" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Trailing-slash redirects no longer crash on non-latin-1 paths: the
<code class="docutils literal notranslate"><span class="pre">Location</span></code> header is percent-encoded (<code class="docutils literal notranslate"><span class="pre">GET</span> <span class="pre">/日本/</span></code> now answers <code class="docutils literal notranslate"><span class="pre">307</span></code> instead
of a 500 from a <code class="docutils literal notranslate"><span class="pre">UnicodeEncodeError</span></code>), and the redirect now matches the
alternate path regardless of request method — <code class="docutils literal notranslate"><span class="pre">POST</span> <span class="pre">/page/</span></code> redirects to
<code class="docutils literal notranslate"><span class="pre">/page</span></code> just like GET does, instead of falling through to a 404.</p></li>
<li><p>A sync view that outlives <code class="docutils literal notranslate"><span class="pre">request_timeout</span></code> can no longer corrupt the
<code class="docutils literal notranslate"><span class="pre">504</span> <span class="pre">Gateway</span> <span class="pre">Timeout</span></code> response: the timeout reply is built on a fresh
<code class="docutils literal notranslate"><span class="pre">Response</span></code>, so the abandoned thread’s late writes land on an inert object.
Headers and cookies set by completed <code class="docutils literal notranslate"><span class="pre">before_request</span></code> hooks (request IDs,
CORS) are carried onto the 504; stale body-framing headers are not.</p></li>
<li><p>The route-resolution cache evicts its least-recently-used entry when full
instead of clearing all 1024 entries wholesale, so high-cardinality
parameterized paths no longer periodically wipe the hot static entries.</p></li>
<li><p>Route registration errors are real exceptions instead of <code class="docutils literal notranslate"><span class="pre">assert</span></code> statements
(which vanish under <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-O</span></code>): a route path without a leading <code class="docutils literal notranslate"><span class="pre">/</span></code>, an
unknown path convertor, and an unknown event type all raise <code class="docutils literal notranslate"><span class="pre">ValueError</span></code>
naming the offender, and a duplicate path parameter (<code class="docutils literal notranslate"><span class="pre">/x/{id}/{id}</span></code>) is
caught up front with a clear message instead of a bare <code class="docutils literal notranslate"><span class="pre">re.error</span></code>.</p></li>
<li><p>The legacy <code class="docutils literal notranslate"><span class="pre">on_event(&quot;shutdown&quot;)</span></code> lifespan path now mirrors the <code class="docutils literal notranslate"><span class="pre">lifespan=</span></code>
path when a shutdown handler raises: app-scoped dependency teardowns still
run and <code class="docutils literal notranslate"><span class="pre">lifespan.shutdown.failed</span></code> is sent, instead of both being skipped.</p></li>
<li><p>Class-based-view 405 responses now include the <code class="docutils literal notranslate"><span class="pre">Allow</span></code> header required by
RFC 9110 §15.5.6, listing the methods the class actually serves via <code class="docutils literal notranslate"><span class="pre">on_*</span></code>
handlers (plus implicit <code class="docutils literal notranslate"><span class="pre">HEAD</span></code> when <code class="docutils literal notranslate"><span class="pre">on_get</span></code> exists).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">QueryDict</span></code> item assignment and <code class="docutils literal notranslate"><span class="pre">update()</span></code> no longer corrupt single-value
reads: assigning a scalar (<code class="docutils literal notranslate"><span class="pre">qd[&quot;x&quot;]</span> <span class="pre">=</span> <span class="pre">&quot;hello&quot;</span></code>) previously stored a bare
string, so reading it back returned the last character. Scalars are stored
as one-element lists, and <code class="docutils literal notranslate"><span class="pre">update()</span></code> from another <code class="docutils literal notranslate"><span class="pre">QueryDict</span></code> merges the
full multi-value lists, matching 8.0.0 semantics.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">req.accepts()</span></code> honors media-range specificity per RFC 9110 §12.5.1: an
explicit <code class="docutils literal notranslate"><span class="pre">q=0</span></code> range now excludes the type even when a broader range
(<code class="docutils literal notranslate"><span class="pre">*/*</span></code> or <code class="docutils literal notranslate"><span class="pre">type/*</span></code>) would match — and a <code class="docutils literal notranslate"><span class="pre">q=0</span></code> wildcard of a <em>different</em>
top-level type no longer vetoes unrelated bare-token lookups.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">req.apparent_encoding</span></code> recognizes valid UTF-8 bodies with a cheap strict
decode and runs chardet detection in a worker thread, so a large body
without a <code class="docutils literal notranslate"><span class="pre">charset=</span></code> parameter no longer stalls the event loop.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">resp.stream_file()</span></code> and <code class="docutils literal notranslate"><span class="pre">resp.download()</span></code> now send <code class="docutils literal notranslate"><span class="pre">Content-Length</span></code>
(computed exactly for full-body, single-range, and multipart byte-range
responses). Replacing the body afterwards (<code class="docutils literal notranslate"><span class="pre">resp.text</span></code>, <code class="docutils literal notranslate"><span class="pre">resp.problem()</span></code>,
<code class="docutils literal notranslate"><span class="pre">resp.created()</span></code>) clears the stale <code class="docutils literal notranslate"><span class="pre">Content-Length</span></code>/<code class="docutils literal notranslate"><span class="pre">Content-Range</span></code>/
<code class="docutils literal notranslate"><span class="pre">Accept-Ranges</span></code> so the response cannot be misframed.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">HEAD</span></code> requests against <code class="docutils literal notranslate"><span class="pre">resp.file()</span></code> no longer read the entire file in the
threadpool just to discard the body — the headers (including the
stat-derived <code class="docutils literal notranslate"><span class="pre">Content-Length</span></code>) are sent without touching the file contents.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">resp.problem()</span></code> serializes extension members through the same type-aware
JSON encoder as <code class="docutils literal notranslate"><span class="pre">resp.media</span></code> (datetimes, UUIDs, Decimals, sets, dataclasses,
Pydantic models, and any custom <code class="docutils literal notranslate"><span class="pre">API(encoder=...)</span></code>) instead of bare
<code class="docutils literal notranslate"><span class="pre">json.dumps</span></code>, so <code class="docutils literal notranslate"><span class="pre">resp.problem(409,</span> <span class="pre">occurred_at=datetime.now())</span></code> no longer
turns into a 500.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">resp.stream()</span></code> and <code class="docutils literal notranslate"><span class="pre">resp.sse()</span></code> raise a descriptive <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> when given
a non-async-generator function, instead of a message-less <code class="docutils literal notranslate"><span class="pre">assert</span></code> that
vanished under <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-O</span></code>.</p></li>
<li><p>OpenAPI parameter schemas for enum and nested Pydantic types no longer emit
dangling <code class="docutils literal notranslate"><span class="pre">$ref</span></code>s or inline <code class="docutils literal notranslate"><span class="pre">$defs</span></code>: referenced definitions are hoisted into
<code class="docutils literal notranslate"><span class="pre">components/schemas</span></code> (same-named models from different modules get distinct
component names) and the generated document passes <code class="docutils literal notranslate"><span class="pre">openapi-spec-validator</span></code>.</p></li>
<li><p>Generated clients (Python, JavaScript, TypeScript, Ruby, PHP) now actually
send the header and cookie parameters they accept.</p></li>
<li><p>Generated clients send <code class="docutils literal notranslate"><span class="pre">Form()</span></code>/<code class="docutils literal notranslate"><span class="pre">File()</span></code> request bodies as
<code class="docutils literal notranslate"><span class="pre">application/x-www-form-urlencoded</span></code> or <code class="docutils literal notranslate"><span class="pre">multipart/form-data</span></code> per the
documented requestBody media type, instead of JSON the server rejected with
422 — in every supported client language. Ruby multipart parts carry proper
filenames (with a <code class="docutils literal notranslate"><span class="pre">[filename,</span> <span class="pre">content]</span></code> pair form), and the PHP client
distinguishes file specs from plain list values.</p></li>
<li><p>WebSocket routes are no longer documented as HTTP GET operations in the
OpenAPI schema.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">API(docs_route=...)</span></code> without <code class="docutils literal notranslate"><span class="pre">openapi=</span></code> now enables schema generation
(defaulting to OpenAPI 3.1.0) as documented, instead of serving a docs page
pointing at a 404 schema. An app that already registered its own route at
the schema path keeps it — the implied route is skipped with a warning.</p></li>
<li><p>Required JSON and form request bodies are marked <code class="docutils literal notranslate"><span class="pre">required:</span> <span class="pre">true</span></code> in the
OpenAPI schema, so generated clients require the body instead of defaulting
it to <code class="docutils literal notranslate"><span class="pre">None</span></code> and always failing at runtime.</p></li>
<li><p>The client generators emit correct code on parameter-name collisions
(<code class="docutils literal notranslate"><span class="pre">user-id</span></code> vs <code class="docutils literal notranslate"><span class="pre">user_id</span></code>, or parameters named <code class="docutils literal notranslate"><span class="pre">body</span></code>/<code class="docutils literal notranslate"><span class="pre">path</span></code>/<code class="docutils literal notranslate"><span class="pre">quote</span></code>):
deduplication and reserved-identifier handling are applied consistently to
signatures, query/header/cookie maps, and path interpolation in all four
generators.</p></li>
<li><p>Optional sequence query parameters (<code class="docutils literal notranslate"><span class="pre">tags:</span> <span class="pre">list[int]</span> <span class="pre">|</span> <span class="pre">None</span> <span class="pre">=</span> <span class="pre">Query(None)</span></code>)
now bind repeated values as a list instead of returning 422 — marker
sequence detection unwraps <code class="docutils literal notranslate"><span class="pre">Optional</span></code>/<code class="docutils literal notranslate"><span class="pre">Union</span></code> annotations.</p></li>
<li><p>An <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code> <code class="docutils literal notranslate"><span class="pre">problem_handler</span></code> is now applied on every error path — the
negotiated 404/500 path, route-level 422/504/405 responses, and
<code class="docutils literal notranslate"><span class="pre">resp.problem()</span></code> — instead of being silently dropped with a logged warning
and a never-awaited coroutine.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">SecurityHeadersMiddleware</span></code> no longer crashes every response when a header
value is <code class="docutils literal notranslate"><span class="pre">None</span></code> — a <code class="docutils literal notranslate"><span class="pre">None</span></code> value in <code class="docutils literal notranslate"><span class="pre">headers=</span></code> now removes that default
header (e.g. <code class="docutils literal notranslate"><span class="pre">headers={&quot;x-frame-options&quot;:</span> <span class="pre">None}</span></code> for embeddable apps).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">responder</span> <span class="pre">run</span> <span class="pre">app.py</span></code> registers the loaded module in <code class="docutils literal notranslate"><span class="pre">sys.modules</span></code> before
executing it, so dataclasses, pickling, and <code class="docutils literal notranslate"><span class="pre">typing.get_type_hints</span></code> inside
loaded apps work. A pre-existing module with the same name is never
clobbered (the target gets a unique key), and only the added entry is
removed if execution fails.</p></li>
<li><p>Multipart part bodies accumulate in a <code class="docutils literal notranslate"><span class="pre">bytearray</span></code> during parsing, avoiding
quadratic copying when the parser delivers a part in many chunks.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">ResponderServer</span></code> no longer crashes when constructed off the main thread or
when <code class="docutils literal notranslate"><span class="pre">is_running()</span></code>/<code class="docutils literal notranslate"><span class="pre">stop()</span></code> are called before <code class="docutils literal notranslate"><span class="pre">start()</span></code>. Signal handlers
are installed by <code class="docutils literal notranslate"><span class="pre">start()</span></code> (main thread only) and restored on <code class="docutils literal notranslate"><span class="pre">stop()</span></code>,
correctly even when multiple servers are stopped out of order.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">API.path_matches_route</span></code> accepts the plain path string its docstring
documents — for HTTP and WebSocket routes — instead of raising <code class="docutils literal notranslate"><span class="pre">TypeError</span></code>;
ASGI scope mappings are still accepted.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">API.session(base_url=...)</span></code> rebuilds the cached test client when called
with a different <code class="docutils literal notranslate"><span class="pre">base_url</span></code> instead of silently returning the previous
client bound to the old address.</p></li>
</ul>
</section>
</section>
<section id="v8-0-0-2026-07-01">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v7.3.0..v8.0.0">v8.0.0</a> - 2026-07-01<a class="headerlink" href="#v8-0-0-2026-07-01" title="Link to this heading"></a></h2>
<section id="id20">
<h3>Added<a class="headerlink" href="#id20" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Standalone router composition: <code class="docutils literal notranslate"><span class="pre">responder.Router</span></code> records route declarations
without an <code class="docutils literal notranslate"><span class="pre">API</span></code> instance — like Flask blueprints or FastAPI’s <code class="docutils literal notranslate"><span class="pre">APIRouter</span></code> —
and <code class="docutils literal notranslate"><span class="pre">api.include_router(router,</span> <span class="pre">prefix=...)</span></code> attaches them. Routers nest
(prefixes compose, tags merge, dependencies concatenate), carry group-level
<code class="docutils literal notranslate"><span class="pre">tags</span></code>/<code class="docutils literal notranslate"><span class="pre">dependencies</span></code>/<code class="docutils literal notranslate"><span class="pre">auth</span></code> defaults that individual routes may override,
scope their <code class="docutils literal notranslate"><span class="pre">before_request</span></code> hooks to the mounted prefix, and can be included
at more than one prefix. Declarations are replayed through <code class="docutils literal notranslate"><span class="pre">api.route()</span></code>, so
auth inheritance, <code class="docutils literal notranslate"><span class="pre">Depends</span></code> guards, and OpenAPI metadata work exactly as if
declared on the API directly. Including a view with auth/tags/dependencies
that conflict with an earlier registration of the same function raises
<code class="docutils literal notranslate"><span class="pre">ValueError</span></code> instead of silently rewriting the earlier route (an
access-control hazard otherwise). <code class="docutils literal notranslate"><span class="pre">api.group()</span></code> remains for quick same-file
prefix grouping.</p></li>
</ul>
</section>
<section id="id21">
<h3>Changed<a class="headerlink" href="#id21" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Text responses now declare their charset the standard way —
<code class="docutils literal notranslate"><span class="pre">Content-Type:</span> <span class="pre">text/...;</span> <span class="pre">charset=&lt;encoding&gt;</span></code> — and <code class="docutils literal notranslate"><span class="pre">resp.encoding</span></code> is honored
when encoding <code class="docutils literal notranslate"><span class="pre">str</span></code> bodies for all text types (previously <code class="docutils literal notranslate"><span class="pre">resp.html</span></code> ignored
it and str bodies fell through to a UTF-8 encode, producing mojibake for e.g.
<code class="docutils literal notranslate"><span class="pre">latin-1</span></code>). The charset parameter is only added when the framework actually
encodes a <code class="docutils literal notranslate"><span class="pre">str</span></code> body; raw <code class="docutils literal notranslate"><span class="pre">bytes</span></code> bodies (e.g. <code class="docutils literal notranslate"><span class="pre">resp.file()</span></code>) keep their bare
media type. The nonstandard <code class="docutils literal notranslate"><span class="pre">Encoding</span></code> response header is no longer sent.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">resp.redirect()</span></code> (and the <code class="docutils literal notranslate"><span class="pre">api.redirect()</span></code> helper) now default to a
method-preserving <code class="docutils literal notranslate"><span class="pre">307</span> <span class="pre">Temporary</span> <span class="pre">Redirect</span></code> instead of <code class="docutils literal notranslate"><span class="pre">301</span> <span class="pre">Moved</span> <span class="pre">Permanently</span></code>,
which browsers cache indefinitely and legacy clients rewrite POST→GET. Pass
<code class="docutils literal notranslate"><span class="pre">permanent=True</span></code> for a <code class="docutils literal notranslate"><span class="pre">308</span> <span class="pre">Permanent</span> <span class="pre">Redirect</span></code>; an explicit <code class="docutils literal notranslate"><span class="pre">status_code=</span></code>
still takes precedence.</p></li>
<li><p>YAML responses are served as <code class="docutils literal notranslate"><span class="pre">application/yaml</span></code> (the RFC 9512 registered
media type) instead of the legacy <code class="docutils literal notranslate"><span class="pre">application/x-yaml</span></code>; the OpenAPI
<code class="docutils literal notranslate"><span class="pre">/schema.yml</span></code> route follows suit. Inbound requests are unaffected — bodies
sent with either media type still parse as YAML, and
<code class="docutils literal notranslate"><span class="pre">Accept:</span> <span class="pre">application/x-yaml</span></code> still negotiates a YAML response.</p></li>
<li><p>An empty or whitespace-only YAML request body now raises <code class="docutils literal notranslate"><span class="pre">400</span> <span class="pre">Bad</span> <span class="pre">Request</span></code>
from <code class="docutils literal notranslate"><span class="pre">req.media()</span></code>, matching the JSON format (previously <code class="docutils literal notranslate"><span class="pre">yaml.safe_load</span></code>
silently returned <code class="docutils literal notranslate"><span class="pre">None</span></code>). An explicit YAML <code class="docutils literal notranslate"><span class="pre">null</span></code> document still parses to
<code class="docutils literal notranslate"><span class="pre">None</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">url_for</span></code> now raises <code class="docutils literal notranslate"><span class="pre">RouteNotFoundError</span></code> (a <code class="docutils literal notranslate"><span class="pre">LookupError</span></code> subclass,
importable as <code class="docutils literal notranslate"><span class="pre">responder.RouteNotFoundError</span></code>) for an unknown endpoint or
route name instead of returning <code class="docutils literal notranslate"><span class="pre">None</span></code> (which rendered a literal “None” in
templates), and generated URLs percent-encode parameter values —
<code class="docutils literal notranslate"><span class="pre">url_for(view,</span> <span class="pre">name=&quot;a</span> <span class="pre">b&quot;)</span></code> yields <code class="docutils literal notranslate"><span class="pre">/file/a%20b</span></code>; <code class="docutils literal notranslate"><span class="pre">{param:path}</span></code> segments
keep their slashes.</p></li>
<li><p>Requests into a WSGI mount no longer build a fresh <code class="docutils literal notranslate"><span class="pre">a2wsgi.WSGIMiddleware</span></code>
(and its per-instance <code class="docutils literal notranslate"><span class="pre">ThreadPoolExecutor</span></code>) on every request; the app is
wrapped once, at mount time.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">API()</span></code> no longer creates <code class="docutils literal notranslate"><span class="pre">static_dir</span></code> implicitly. Merely instantiating
<code class="docutils literal notranslate"><span class="pre">API()</span></code> used to <code class="docutils literal notranslate"><span class="pre">mkdir</span></code> an empty <code class="docutils literal notranslate"><span class="pre">static/</span></code> into the working directory (and
failed on read-only filesystems); the default <code class="docutils literal notranslate"><span class="pre">static/</span></code> is now mounted only
when the directory already exists, and an explicitly passed <code class="docutils literal notranslate"><span class="pre">static_dir</span></code> that
doesn’t exist raises <code class="docutils literal notranslate"><span class="pre">FileNotFoundError</span></code> at construction. <code class="docutils literal notranslate"><span class="pre">static_dir=None</span></code>
still disables static serving, and the docstrings no longer claim
<code class="docutils literal notranslate"><span class="pre">static_dir</span></code>/<code class="docutils literal notranslate"><span class="pre">templates_dir</span></code> are “created for you”.</p></li>
</ul>
</section>
<section id="id22">
<h3>Fixed<a class="headerlink" href="#id22" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">Request.cookies</span></code> no longer silently drops cookies: the <code class="docutils literal notranslate"><span class="pre">Cookie</span></code> header is
now parsed with Starlette’s tolerant parser instead of
<code class="docutils literal notranslate"><span class="pre">http.cookies.SimpleCookie</span></code>, which aborted at the first nonconforming token
(e.g. <code class="docutils literal notranslate"><span class="pre">b[]=2</span></code>) and discarded that cookie and every one after it.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Response.headers</span></code> is now a case-insensitive, case-preserving mapping, so a
handler setting <code class="docutils literal notranslate"><span class="pre">resp.headers['content-type']</span></code> replaces the framework’s
<code class="docutils literal notranslate"><span class="pre">Content-Type</span></code> instead of emitting both headers on the wire (and
<code class="docutils literal notranslate"><span class="pre">no_content()</span></code> no longer needs to pop both spellings). <code class="docutils literal notranslate"><span class="pre">CaseInsensitiveDict</span></code>
construction from a mapping, <code class="docutils literal notranslate"><span class="pre">|=</span></code>/<code class="docutils literal notranslate"><span class="pre">|</span></code>, <code class="docutils literal notranslate"><span class="pre">.copy()</span></code>, and <code class="docutils literal notranslate"><span class="pre">.fromkeys()</span></code> are also
case-insensitive now — each previously bypassed the lowercasing — iteration
preserves the casing keys were set with, and instances survive <code class="docutils literal notranslate"><span class="pre">pickle</span></code>,
<code class="docutils literal notranslate"><span class="pre">copy.copy</span></code>, and <code class="docutils literal notranslate"><span class="pre">copy.deepcopy</span></code> round-trips.</p></li>
<li><p>Background tasks now support async functions: <code class="docutils literal notranslate"><span class="pre">&#64;api.background.task</span></code> and
<code class="docutils literal notranslate"><span class="pre">api.background.run</span></code> drive an <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code> to completion via <code class="docutils literal notranslate"><span class="pre">asyncio.run</span></code> on
the worker thread (a <code class="docutils literal notranslate"><span class="pre">functools.partial</span></code> wrapping one works too). Previously
an async task silently produced a never-awaited coroutine and the job never
ran. Background worker threads are also now named <code class="docutils literal notranslate"><span class="pre">responder-background-*</span></code>
for easier debugging. Sync task behavior is unchanged.</p></li>
<li><p>Assigning <code class="docutils literal notranslate"><span class="pre">templates.context</span> <span class="pre">=</span> <span class="pre">{...}</span></code> no longer wipes Jinja2’s built-in
globals (<code class="docutils literal notranslate"><span class="pre">range</span></code>, <code class="docutils literal notranslate"><span class="pre">namespace</span></code>, <code class="docutils literal notranslate"><span class="pre">cycler</span></code>, <code class="docutils literal notranslate"><span class="pre">joiner</span></code>, <code class="docutils literal notranslate"><span class="pre">lipsum</span></code>, <code class="docutils literal notranslate"><span class="pre">dict</span></code>) —
previously any template using <code class="docutils literal notranslate"><span class="pre">range()</span></code> after a context assignment raised
<code class="docutils literal notranslate"><span class="pre">UndefinedError</span></code>. The setter now updates the globals dict in place (keeping
the sync and async environments sharing one globals object), and reassigning
the context restores any built-in a previous assignment had shadowed.</p></li>
<li><p>The GraphQL view now executes queries with <code class="docutils literal notranslate"><span class="pre">schema.execute_async</span></code>, so
<code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span></code> resolvers (first-class in graphene 3) resolve correctly instead
of failing with a “coroutine was never awaited” error, and resolvers can
yield the event loop while they await. The query document is also parsed once
and shared by the GET-mutation guard and introspection/depth validation
instead of being re-parsed by each.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">API(lifespan=...)</span></code> no longer silently disables <code class="docutils literal notranslate"><span class="pre">on_event</span></code> handlers: startup
events run after the lifespan context manager is entered and shutdown events
before it exits, so background-task draining (registered as a shutdown event)
is no longer skipped. A raising lifespan <code class="docutils literal notranslate"><span class="pre">__aexit__</span></code> now still tears down
app-scoped dependencies and reports <code class="docutils literal notranslate"><span class="pre">lifespan.shutdown.failed</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">add_route(default=True)</span></code> with a Responder <code class="docutils literal notranslate"><span class="pre">(req,</span> <span class="pre">resp)</span></code> view no longer
crashes every unmatched request (the default endpoint was invoked ASGI-style,
raising <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> → 500). A view-style default is now dispatched through
normal route semantics — before/after hooks, dependency injection, and
response handling — with empty path params; ASGI-style defaults (including
the built-in 404) are unchanged.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">HEAD</span></code> requests to a class-based view that defines only <code class="docutils literal notranslate"><span class="pre">on_get</span></code> now fall
back to <code class="docutils literal notranslate"><span class="pre">on_get</span></code> (with the response body stripped) instead of returning 405,
matching the implicit HEAD support function views already had.</p></li>
<li><p>A mount prefix with a trailing slash (<code class="docutils literal notranslate"><span class="pre">api.mount(&quot;/admin/&quot;,</span> <span class="pre">app)</span></code>) now
matches subpaths; the prefix is normalized at mount time, and the
empty-prefix root mount still catches everything.</p></li>
<li><p>An unhandled exception in a WebSocket handler now closes the socket with code
1011 (internal error) before re-raising, so clients can tell a server bug
from a network drop instead of seeing an abnormal 1006 with no close frame.</p></li>
<li><p>Two distinct dependency providers that share a <code class="docutils literal notranslate"><span class="pre">__name__</span></code> (two functions both
named <code class="docutils literal notranslate"><span class="pre">get_db</span></code>, or nested inline lambda <code class="docutils literal notranslate"><span class="pre">Depends</span></code>) no longer trip a false
<code class="docutils literal notranslate"><span class="pre">DependencyCycleError</span></code> — cycle detection now tracks provider identity,
keeping names only for the error message.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">url_for</span></code> no longer raises <code class="docutils literal notranslate"><span class="pre">AttributeError</span></code> when any registered route uses a
callable-instance endpoint without a <code class="docutils literal notranslate"><span class="pre">__name__</span></code> (e.g. a mounted
<code class="docutils literal notranslate"><span class="pre">GraphQLView</span></code>); the by-name fallback scan now skips such endpoints.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">api.group(...).route(None)</span></code> now raises the usual “a route path is required”
error instead of silently registering a literal <code class="docutils literal notranslate"><span class="pre">/prefixNone</span></code> path built from
the f-string.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">jinja2</span></code>, <code class="docutils literal notranslate"><span class="pre">pyyaml</span></code>, and <code class="docutils literal notranslate"><span class="pre">itsdangerous</span></code> are now declared as direct
dependencies. Responder imports them directly (templates, YAML content
negotiation, and cookie-based session middleware) but previously received
them only transitively via the <code class="docutils literal notranslate"><span class="pre">starlette[full]</span></code> extra. <code class="docutils literal notranslate"><span class="pre">python-multipart</span></code>
now carries a <code class="docutils literal notranslate"><span class="pre">&gt;=0.0.12</span></code> floor (the first release that ships the
<code class="docutils literal notranslate"><span class="pre">python_multipart</span></code> module name Responder imports), the <code class="docutils literal notranslate"><span class="pre">apispec</span></code> and
<code class="docutils literal notranslate"><span class="pre">marshmallow</span></code> floors were raised to <code class="docutils literal notranslate"><span class="pre">&gt;=6.6</span></code> and <code class="docutils literal notranslate"><span class="pre">&gt;=3.20</span></code> to match what the
OpenAPI extension is tested against, and the build system now requires
<code class="docutils literal notranslate"><span class="pre">setuptools&gt;=77</span></code>, the first version that supports the PEP 639 SPDX
<code class="docutils literal notranslate"><span class="pre">license</span> <span class="pre">=</span> <span class="pre">&quot;Apache-2.0&quot;</span></code> expression (the previous <code class="docutils literal notranslate"><span class="pre">&gt;=42</span></code> pin could not build
the project).</p></li>
</ul>
</section>
<section id="id23">
<h3>Security<a class="headerlink" href="#id23" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">resp.download()</span></code> sanitizes user-derived filenames in <code class="docutils literal notranslate"><span class="pre">Content-Disposition</span></code>:
CR, LF, and NUL are stripped (they allowed header injection), <code class="docutils literal notranslate"><span class="pre">&quot;</span></code> and <code class="docutils literal notranslate"><span class="pre">\</span></code> are
backslash-escaped in the quoted-string (a quote could break out of
<code class="docutils literal notranslate"><span class="pre">filename=&quot;...&quot;</span></code>), and names containing characters outside the HTTP token set
now also carry the RFC 5987 <code class="docutils literal notranslate"><span class="pre">filename*=</span></code> form (non-ASCII names keep the
<code class="docutils literal notranslate"><span class="pre">filename*=</span></code>-only form).</p></li>
<li><p>The in-memory <code class="docutils literal notranslate"><span class="pre">MemorySessionBackend</span></code> now bounds its store (LRU eviction,
<code class="docutils literal notranslate"><span class="pre">max_keys</span></code>, default 100,000) and opportunistically sweeps expired entries on
writes, so an attacker rotating session cookies — or plain abandoned
sessions, previously deleted only on a <code class="docutils literal notranslate"><span class="pre">get()</span></code> with that exact ID — can no
longer grow process memory without bound. Eviction removes earliest-expiry
entries first, and operations are lock-guarded, as they run on threadpool
workers.</p></li>
</ul>
</section>
</section>
<section id="v7-3-0-2026-07-01">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v7.2.1..v7.3.0">v7.3.0</a> - 2026-07-01<a class="headerlink" href="#v7-3-0-2026-07-01" title="Link to this heading"></a></h2>
<section id="id24">
<h3>Added<a class="headerlink" href="#id24" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Inline <code class="docutils literal notranslate"><span class="pre">Depends(...)</span></code> can now nest inside a provider (sub-dependency chains),
matching FastAPI. Previously only named <code class="docutils literal notranslate"><span class="pre">&#64;api.dependency()</span></code> providers could
chain; a provider with an inline <code class="docutils literal notranslate"><span class="pre">Depends</span></code> parameter raised
<code class="docutils literal notranslate"><span class="pre">DependencyResolutionError</span></code>.</p></li>
<li><p>A developer <code class="docutils literal notranslate"><span class="pre">Makefile</span></code>: bare <code class="docutils literal notranslate"><span class="pre">make</span></code> lists tasks (<code class="docutils literal notranslate"><span class="pre">test</span></code>, <code class="docutils literal notranslate"><span class="pre">lint</span></code>, <code class="docutils literal notranslate"><span class="pre">types</span></code>,
<code class="docutils literal notranslate"><span class="pre">docs</span></code>, <code class="docutils literal notranslate"><span class="pre">build</span></code>, <code class="docutils literal notranslate"><span class="pre">check</span></code>, …), all run through <code class="docutils literal notranslate"><span class="pre">uv</span></code>. <code class="docutils literal notranslate"><span class="pre">make</span> <span class="pre">test</span></code> and
<code class="docutils literal notranslate"><span class="pre">make</span> <span class="pre">docs</span></code> depend on <code class="docutils literal notranslate"><span class="pre">make</span> <span class="pre">uv-sync</span></code>.</p></li>
</ul>
</section>
<section id="id25">
<h3>Changed<a class="headerlink" href="#id25" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">Request.accepts()</span></code> now honors <code class="docutils literal notranslate"><span class="pre">Accept</span></code> media ranges (<code class="docutils literal notranslate"><span class="pre">*/*</span></code>, <code class="docutils literal notranslate"><span class="pre">type/*</span></code>) and
q-values (a <code class="docutils literal notranslate"><span class="pre">q=0</span></code> range is not acceptable) instead of substring-matching the
raw header. An absent <code class="docutils literal notranslate"><span class="pre">Accept</span></code> accepts anything.</p></li>
<li><p>Request body decoding honors the standard <code class="docutils literal notranslate"><span class="pre">Content-Type</span></code> <code class="docutils literal notranslate"><span class="pre">charset=</span></code> parameter,
using chardet only when no charset is declared.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Request.media()</span></code> auto-detects MessagePack (<code class="docutils literal notranslate"><span class="pre">application/x-msgpack</span></code>) bodies.</p></li>
<li><p>Dependency and request-body-model signature inspection is now memoized on the
per-request path, and large <code class="docutils literal notranslate"><span class="pre">auto_etag</span></code> response bodies are hashed off the
event loop.</p></li>
<li><p>The project <code class="docutils literal notranslate"><span class="pre">Homepage</span></code> URL now points at the documentation site.</p></li>
</ul>
</section>
<section id="id26">
<h3>Fixed<a class="headerlink" href="#id26" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Multipart form parsing no longer emits file parts (or their filenames) as
phantom form fields, and correctly parses unquoted field names — it now uses a
real Content-Disposition parser.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">enable_logging</span></code> no longer drops a request whose <code class="docutils literal notranslate"><span class="pre">X-Request-ID</span></code> is not valid
UTF-8; the header is decoded as latin-1, matching <code class="docutils literal notranslate"><span class="pre">RequestIDMiddleware</span></code>.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">responder.ext.query</span></code> descending sort keeps <code class="docutils literal notranslate"><span class="pre">None</span></code> values last, per its
documented contract (it previously pushed them to the front).</p></li>
<li><p>Mounted sub-app WSGI-vs-ASGI detection is decided from the call signature
rather than the text of a raised <code class="docutils literal notranslate"><span class="pre">TypeError</span></code>, so a genuine <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> inside a
mounted ASGI app keeps its real traceback instead of being misclassified.</p></li>
<li><p>A user <code class="docutils literal notranslate"><span class="pre">lifespan(app)</span></code> context manager now receives the <code class="docutils literal notranslate"><span class="pre">API</span></code> instance instead
of <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">MetricsCollector</span></code> reads/writes are lock-guarded, so a concurrent <code class="docutils literal notranslate"><span class="pre">/metrics</span></code>
scrape no longer risks <code class="docutils literal notranslate"><span class="pre">RuntimeError:</span> <span class="pre">dictionary</span> <span class="pre">changed</span> <span class="pre">size</span> <span class="pre">during</span> <span class="pre">iteration</span></code> and counts stay exact on free-threaded CPython.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Templates.render_async</span></code> uses a dedicated always-async Jinja environment
instead of toggling <code class="docutils literal notranslate"><span class="pre">is_async</span></code> on a shared one, fixing a race between
concurrent sync and async renders.</p></li>
</ul>
</section>
<section id="id27">
<h3>Security<a class="headerlink" href="#id27" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>The in-memory rate-limit <code class="docutils literal notranslate"><span class="pre">MemoryBackend</span></code> now bounds its key set (LRU eviction,
<code class="docutils literal notranslate"><span class="pre">max_keys</span></code>), so a client rotating source IPs (or spoofing <code class="docutils literal notranslate"><span class="pre">X-Forwarded-For</span></code>)
can no longer grow process memory without bound.</p></li>
<li><p>The Server-Sent Events heartbeat queue is now bounded, restoring producer
backpressure so a slow/stalled client can’t make it buffer without limit.</p></li>
</ul>
</section>
</section>
<section id="v7-2-1-2026-07-01">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v7.2.0..v7.2.1">v7.2.1</a> - 2026-07-01<a class="headerlink" href="#v7-2-1-2026-07-01" title="Link to this heading"></a></h2>
<section id="id28">
<h3>Security<a class="headerlink" href="#id28" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>The GraphQL view now rejects mutations sent over HTTP <code class="docutils literal notranslate"><span class="pre">GET</span></code> (returns <code class="docutils literal notranslate"><span class="pre">405</span></code>
with <code class="docutils literal notranslate"><span class="pre">Allow:</span> <span class="pre">POST</span></code>). <code class="docutils literal notranslate"><span class="pre">GET</span></code> must be safe/idempotent; running a mutation via
<code class="docutils literal notranslate"><span class="pre">GET</span> <span class="pre">/graphql?query=mutation{...}</span></code> made it CSRF-able (a plain <code class="docutils literal notranslate"><span class="pre">&lt;img</span> <span class="pre">src&gt;</span></code>
would trigger it with the victim’s cookies) and cacheable. Query operations
over <code class="docutils literal notranslate"><span class="pre">GET</span></code> are unaffected.</p></li>
</ul>
</section>
<section id="id29">
<h3>Fixed<a class="headerlink" href="#id29" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>The client generator now escapes path-parameter names when interpolating them
into generated string literals (Python <code class="docutils literal notranslate"><span class="pre">repr</span></code>, JS via the JS escaper, Ruby via
a new single-quoted escaper). A name containing a quote or backslash in an
(untrusted) OpenAPI spec previously produced a client that failed to parse.</p></li>
</ul>
</section>
</section>
<section id="v7-2-0-2026-07-01">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v7.1.3..v7.2.0">v7.2.0</a> - 2026-07-01<a class="headerlink" href="#v7-2-0-2026-07-01" title="Link to this heading"></a></h2>
<section id="id30">
<h3>Security<a class="headerlink" href="#id30" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Server-Sent Events frames can no longer be spoofed via caller-supplied field
values. A <code class="docutils literal notranslate"><span class="pre">\r</span></code> or <code class="docutils literal notranslate"><span class="pre">\n</span></code> in an SSE <code class="docutils literal notranslate"><span class="pre">event</span></code>, <code class="docutils literal notranslate"><span class="pre">id</span></code>, <code class="docutils literal notranslate"><span class="pre">retry</span></code>, or comment field is
now stripped (these are single-line fields; a line break would terminate the
field and inject additional SSE lines/frames), and <code class="docutils literal notranslate"><span class="pre">data</span></code> splits on any line
terminator (<code class="docutils literal notranslate"><span class="pre">\r\n</span></code>, <code class="docutils literal notranslate"><span class="pre">\r</span></code>, <code class="docutils literal notranslate"><span class="pre">\n</span></code>) so a lone <code class="docutils literal notranslate"><span class="pre">\r</span></code> can’t inject a new field.</p></li>
</ul>
</section>
<section id="id31">
<h3>Added<a class="headerlink" href="#id31" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">API(ws_idle_timeout=...)</span></code> closes a WebSocket that waits too long for the next
inbound message (close code <code class="docutils literal notranslate"><span class="pre">1001</span></code>). The deadline resets on every message, so
it bounds idle time between messages, not total connection lifetime. Defaults
to <code class="docutils literal notranslate"><span class="pre">None</span></code> (unlimited), preserving existing behavior.</p></li>
</ul>
</section>
<section id="id32">
<h3>Changed<a class="headerlink" href="#id32" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Tightened the mypy configuration: <code class="docutils literal notranslate"><span class="pre">no_implicit_optional</span></code>, <code class="docutils literal notranslate"><span class="pre">warn_unused_ignores</span></code>,
and <code class="docutils literal notranslate"><span class="pre">warn_redundant_casts</span></code> are now on. Removed the blanket
<code class="docutils literal notranslate"><span class="pre">implicit_optional</span> <span class="pre">=</span> <span class="pre">true</span></code>. Cleaned up the stale <code class="docutils literal notranslate"><span class="pre">#</span> <span class="pre">type:</span> <span class="pre">ignore</span></code> comments this
surfaced.</p></li>
<li><p>Completed type annotations across the codebase and enabled mypy
<code class="docutils literal notranslate"><span class="pre">disallow_incomplete_defs</span></code>, so partially-annotated functions now fail type
checking. Annotations only — no runtime behavior changed.</p></li>
<li><p>Dropped the separate “Generated client syntax checks” CI job.</p></li>
</ul>
</section>
<section id="id33">
<h3>Fixed<a class="headerlink" href="#id33" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Synchronous lifecycle handlers (<code class="docutils literal notranslate"><span class="pre">startup</span></code>/<code class="docutils literal notranslate"><span class="pre">shutdown</span></code> events) and synchronous
exception handlers now run in a thread pool instead of directly on the event
loop, so a blocking call in one no longer stalls the server.</p></li>
<li><p>Content-Type matching is now case-insensitive, per RFC 7231. Requests sent
with e.g. <code class="docutils literal notranslate"><span class="pre">Application/JSON</span></code> or <code class="docutils literal notranslate"><span class="pre">Multipart/Form-Data</span></code> are negotiated and
parsed correctly instead of falling through to the wrong parser. Affects
<code class="docutils literal notranslate"><span class="pre">Request.is_json</span></code>, <code class="docutils literal notranslate"><span class="pre">Request.media()</span></code> format auto-detection, and multipart
form parsing (including an uppercased <code class="docutils literal notranslate"><span class="pre">Boundary</span></code> parameter name).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">ResponderServer.__init__</span></code>’s <code class="docutils literal notranslate"><span class="pre">limit_max_requests</span></code> parameter was annotated
<code class="docutils literal notranslate"><span class="pre">int</span></code> but defaulted to <code class="docutils literal notranslate"><span class="pre">None</span></code>; it is now <code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">|</span> <span class="pre">None</span></code>.</p></li>
</ul>
</section>
</section>
<section id="v7-1-3-2026-07-01">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v7.1.2..v7.1.3">v7.1.3</a> - 2026-07-01<a class="headerlink" href="#v7-1-3-2026-07-01" title="Link to this heading"></a></h2>
<section id="id34">
<h3>Fixed<a class="headerlink" href="#id34" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">RedisBackend</span></code>/<code class="docutils literal notranslate"><span class="pre">AsyncRedisBackend</span></code> rate limiters now increment the counter
and set its expiry in a single atomic server-side step (Lua <code class="docutils literal notranslate"><span class="pre">EVAL</span></code>). The
previous separate <code class="docutils literal notranslate"><span class="pre">INCR</span></code> + <code class="docutils literal notranslate"><span class="pre">EXPIRE</span></code> calls could leave a key without a TTL if
the process died between them, locking that client out until manual eviction.</p></li>
<li><p>Background tasks submitted via <code class="docutils literal notranslate"><span class="pre">api.background</span></code> are now drained on application
shutdown instead of being abandoned, via a registered shutdown handler that
calls <code class="docutils literal notranslate"><span class="pre">BackgroundQueue.shutdown()</span></code>.</p></li>
</ul>
</section>
<section id="id35">
<h3>Changed<a class="headerlink" href="#id35" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>CI now runs <code class="docutils literal notranslate"><span class="pre">ruff</span> <span class="pre">check</span></code> and <code class="docutils literal notranslate"><span class="pre">mypy</span></code> on every push and pull request (new
<code class="docutils literal notranslate"><span class="pre">Lint</span> <span class="pre">&amp;</span> <span class="pre">Types</span></code> workflow), not just during the manual release guard.</p></li>
</ul>
</section>
</section>
<section id="v7-1-2-2026-06-30">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v7.1.1..v7.1.2">v7.1.2</a> - 2026-06-30<a class="headerlink" href="#v7-1-2-2026-06-30" title="Link to this heading"></a></h2>
<section id="id36">
<h3>Added<a class="headerlink" href="#id36" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>New example apps: <code class="docutils literal notranslate"><span class="pre">examples/todo.py</span></code>, <code class="docutils literal notranslate"><span class="pre">examples/fortunes.py</span></code>,
<code class="docutils literal notranslate"><span class="pre">examples/shortlinks.py</span></code>, <code class="docutils literal notranslate"><span class="pre">examples/tarot.py</span></code>, and <code class="docutils literal notranslate"><span class="pre">examples/webhooks.py</span></code>.</p></li>
<li><p>Modernized <code class="docutils literal notranslate"><span class="pre">examples/helloworld.py</span></code>, <code class="docutils literal notranslate"><span class="pre">lifespan.py</span></code>, <code class="docutils literal notranslate"><span class="pre">marimo_mount.py</span></code>,
<code class="docutils literal notranslate"><span class="pre">rest_api.py</span></code>, <code class="docutils literal notranslate"><span class="pre">sse_stream.py</span></code>, <code class="docutils literal notranslate"><span class="pre">user.py</span></code>, and <code class="docutils literal notranslate"><span class="pre">websocket_chat.py</span></code>, with
matching coverage in <code class="docutils literal notranslate"><span class="pre">tests/test_examples.py</span></code>.</p></li>
</ul>
</section>
<section id="id37">
<h3>Fixed<a class="headerlink" href="#id37" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">RateLimiter</span></code> and <code class="docutils literal notranslate"><span class="pre">enable_logging</span></code>’s <code class="docutils literal notranslate"><span class="pre">LoggingMiddleware</span></code> keyed/recorded the
client IP from the TCP peer only, which behind any reverse proxy is the
proxy itself — every visitor shared one rate-limit bucket and access logs
showed the proxy’s address for every request. Both now accept
<code class="docutils literal notranslate"><span class="pre">trust_proxy_headers=True</span></code> to read the real client from
<code class="docutils literal notranslate"><span class="pre">X-Forwarded-For</span></code>/<code class="docutils literal notranslate"><span class="pre">X-Real-IP</span></code> instead (opt-in, since trusting those headers
without a proxy in front lets a client spoof its own address).</p></li>
</ul>
</section>
</section>
<section id="v7-1-1-2026-06-30">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v7.1.0..v7.1.1">v7.1.1</a> - 2026-06-30<a class="headerlink" href="#v7-1-1-2026-06-30" title="Link to this heading"></a></h2>
<section id="id38">
<h3>Added<a class="headerlink" href="#id38" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">examples/atelier.py</span></code> is now the canonical showcase app and contract fixture
for auth policies, OpenAPI metadata, response helpers, problem details, and
generated clients.</p></li>
</ul>
</section>
<section id="id39">
<h3>Fixed<a class="headerlink" href="#id39" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Auth-injected <code class="docutils literal notranslate"><span class="pre">user</span></code>, <code class="docutils literal notranslate"><span class="pre">principal</span></code>, and <code class="docutils literal notranslate"><span class="pre">auth</span></code> parameters are no longer treated
as request-body Pydantic models on routes with JSON bodies.</p></li>
<li><p>Generated clients now keep scanning success responses until they find a JSON
schema, instead of giving up when an earlier 2xx response has no body.</p></li>
</ul>
</section>
</section>
<section id="v7-1-0-2026-06-30">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v7.0.5..v7.1.0">v7.1.0</a> - 2026-06-30<a class="headerlink" href="#v7-1-0-2026-06-30" title="Link to this heading"></a></h2>
<section id="id40">
<h3>Added<a class="headerlink" href="#id40" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">api.policy(name,</span> <span class="pre">auth)</span></code> creates named, reusable auth policy wrappers without
changing the wrapped auth scheme’s runtime or OpenAPI behavior.</p></li>
<li><p>Route decorators now accept <code class="docutils literal notranslate"><span class="pre">responses=</span></code>, <code class="docutils literal notranslate"><span class="pre">examples=</span></code>, <code class="docutils literal notranslate"><span class="pre">response_examples=</span></code>,
and <code class="docutils literal notranslate"><span class="pre">openapi_extra=</span></code> for nearby OpenAPI operation authoring that deep-merges
with generated schemas and framework error responses.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">resp.created(...)</span></code>, <code class="docutils literal notranslate"><span class="pre">resp.no_content()</span></code>, and <code class="docutils literal notranslate"><span class="pre">resp.problem(...)</span></code> provide
focused helpers for common REST responses and manual problem-details payloads.</p></li>
<li><p>A canonical contract fixture now validates a representative OpenAPI document
and generated Python client against the same in-process app.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">scripts/release.py</span></code> orchestrates the release guard, tagging, GitHub release
creation, package build, and Twine upload with a dry-run default.</p></li>
</ul>
</section>
</section>
<section id="v7-0-5-2026-06-30">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v7.0.4..v7.0.5">v7.0.5</a> - 2026-06-30<a class="headerlink" href="#v7-0-5-2026-06-30" title="Link to this heading"></a></h2>
<section id="id41">
<h3>Added<a class="headerlink" href="#id41" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Generated OpenAPI documents are now validated in tests for both OpenAPI 3.0.x
and 3.1.x, including problem-details and legacy-error modes.</p></li>
<li><p>A <code class="docutils literal notranslate"><span class="pre">scripts/release_check.py</span></code> guard verifies release metadata, optional clean
tree and tag state, tests, lint, types, docs, package builds, wheel contents,
and <code class="docutils literal notranslate"><span class="pre">twine</span> <span class="pre">check</span></code>.</p></li>
<li><p>Runtime contracts documentation now describes framework error responses, auth
inheritance, dependency lifecycle, response-model failures, and OpenAPI
defaults.</p></li>
</ul>
</section>
<section id="id42">
<h3>Changed<a class="headerlink" href="#id42" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Wheels now only package <code class="docutils literal notranslate"><span class="pre">responder</span></code> and its declared package data, keeping
top-level docs, examples, and tests out of the installed wheel.</p></li>
<li><p>CI now runs the release guard’s metadata, build, wheel-content, and
<code class="docutils literal notranslate"><span class="pre">twine</span> <span class="pre">check</span></code> path on every push and pull request.</p></li>
</ul>
</section>
<section id="id43">
<h3>Fixed<a class="headerlink" href="#id43" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>The Sphinx docs build now treats Markdown files as sources, making existing
Markdown project pages and the changelog symlink resolvable from the toctree.</p></li>
</ul>
</section>
</section>
<section id="v7-0-4-2026-06-30">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v7.0.3..v7.0.4">v7.0.4</a> - 2026-06-30<a class="headerlink" href="#v7-0-4-2026-06-30" title="Link to this heading"></a></h2>
<section id="id44">
<h3>Fixed<a class="headerlink" href="#id44" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>HEAD responses now send headers without an ASGI response body while preserving
the <code class="docutils literal notranslate"><span class="pre">Content-Length</span></code> a GET would have produced for non-streaming responses.</p></li>
<li><p>Query-string parameters with blank values (for example <code class="docutils literal notranslate"><span class="pre">?q=</span></code>) are preserved
instead of being treated as missing.</p></li>
<li><p>Mutating <code class="docutils literal notranslate"><span class="pre">req.path_params</span></code> during a request can no longer poison the route
resolution cache for later requests to the same concrete path.</p></li>
</ul>
</section>
</section>
<section id="v7-0-3-2026-06-30">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v7.0.2..v7.0.3">v7.0.3</a> - 2026-06-30<a class="headerlink" href="#v7-0-3-2026-06-30" title="Link to this heading"></a></h2>
<section id="id45">
<h3>Fixed<a class="headerlink" href="#id45" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>OpenAPI now documents legacy JSON error responses when
<code class="docutils literal notranslate"><span class="pre">API(problem_details=False)</span></code> is set, and omits the <code class="docutils literal notranslate"><span class="pre">ProblemDetails</span></code> schema in
that mode.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">auth.optional()</span></code> now rejects malformed <code class="docutils literal notranslate"><span class="pre">Authorization</span></code> headers instead of
treating them as anonymous requests.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">problem_handler</span></code> now receives the underlying exception for validation,
response-model, and after-hook failures, and a failing handler falls back to
the original framework payload.</p></li>
<li><p>Scoped auth insufficient-scope challenges now keep valid
<code class="docutils literal notranslate"><span class="pre">WWW-Authenticate</span></code> formatting when the base challenge already has parameters.</p></li>
<li><p>Dependency-resolution errors no longer duplicate the active dependency in the
reported chain.</p></li>
</ul>
</section>
</section>
<section id="v7-0-2-2026-06-30">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v7.0.1..v7.0.2">v7.0.2</a> - 2026-06-30<a class="headerlink" href="#v7-0-2-2026-06-30" title="Link to this heading"></a></h2>
<section id="id46">
<h3>Added<a class="headerlink" href="#id46" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">API(problem_handler=...)</span></code> can enrich framework-generated
<code class="docutils literal notranslate"><span class="pre">application/problem+json</span></code> payloads with fields such as <code class="docutils literal notranslate"><span class="pre">type</span></code>, <code class="docutils literal notranslate"><span class="pre">instance</span></code>,
application error codes, or links.</p></li>
<li><p>Problem-details payloads include <code class="docutils literal notranslate"><span class="pre">request_id</span></code> when request ID middleware or
structured logging is enabled.</p></li>
<li><p>OpenAPI generation now registers a reusable <code class="docutils literal notranslate"><span class="pre">ProblemDetails</span></code> schema and
documents common framework error responses (<code class="docutils literal notranslate"><span class="pre">400</span></code>, <code class="docutils literal notranslate"><span class="pre">401</span></code>, <code class="docutils literal notranslate"><span class="pre">403</span></code>, <code class="docutils literal notranslate"><span class="pre">404</span></code>,
<code class="docutils literal notranslate"><span class="pre">405</span></code>, <code class="docutils literal notranslate"><span class="pre">413</span></code>, <code class="docutils literal notranslate"><span class="pre">422</span></code>, <code class="docutils literal notranslate"><span class="pre">500</span></code>, and <code class="docutils literal notranslate"><span class="pre">504</span></code> when configured).</p></li>
<li><p>OpenAPI operations now receive default <code class="docutils literal notranslate"><span class="pre">operationId</span></code>, <code class="docutils literal notranslate"><span class="pre">summary</span></code>, and tags
when route metadata does not supply them.</p></li>
<li><p>Generated Python, JavaScript, TypeScript, Ruby, and PHP clients expose parsed
problem details on <code class="docutils literal notranslate"><span class="pre">APIError.problem</span></code>; Python also surfaces <code class="docutils literal notranslate"><span class="pre">title</span></code>, <code class="docutils literal notranslate"><span class="pre">detail</span></code>,
and <code class="docutils literal notranslate"><span class="pre">errors</span></code> convenience attributes.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">auth.optional()</span></code> accepts missing credentials while still rejecting invalid
credentials, injecting <code class="docutils literal notranslate"><span class="pre">None</span></code> for anonymous requests and documenting optional
security in OpenAPI.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">API(trace_dispatch=True)</span></code> emits debug logs for the documented dispatch
stages: before hooks, auth, dependencies, handlers, and after hooks.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">responder.testing.assert_problem(...)</span></code> provides a small assertion helper for
problem-details responses.</p></li>
</ul>
</section>
<section id="id47">
<h3>Changed<a class="headerlink" href="#id47" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Scoped auth failures now include a <code class="docutils literal notranslate"><span class="pre">WWW-Authenticate</span></code> insufficient-scope
challenge when the wrapped scheme provides a challenge.</p></li>
<li><p>Dependency-resolution errors include the dependency chain being resolved.</p></li>
</ul>
</section>
</section>
<section id="v7-0-1-2026-06-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v7.0.0..v7.0.1">v7.0.1</a> - 2026-06-29<a class="headerlink" href="#v7-0-1-2026-06-29" title="Link to this heading"></a></h2>
<section id="id48">
<h3>Fixed<a class="headerlink" href="#id48" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Problem-details responses for <code class="docutils literal notranslate"><span class="pre">413</span></code> errors now use the RFC 9110 title
<code class="docutils literal notranslate"><span class="pre">Content</span> <span class="pre">Too</span> <span class="pre">Large</span></code> consistently across Python runtimes.</p></li>
<li><p>CI now installs the checked-out package editable during tests so cached wheels
cannot mask source changes during release validation.</p></li>
</ul>
</section>
</section>
<section id="v7-0-0-2026-06-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v6.6.1..v7.0.0">v7.0.0</a> - 2026-06-29<a class="headerlink" href="#v7-0-0-2026-06-29" title="Link to this heading"></a></h2>
<p>A major release focused on explicit runtime contracts: problem details by
default, first-class app auth (with scope/role checks), route-level dependency
guards, and clearer optional production-server packaging. Python 3.11 is now the
minimum, and the deprecated <code class="docutils literal notranslate"><span class="pre">request_model=</span></code> route option has been removed.</p>
<section id="id49">
<h3>Added<a class="headerlink" href="#id49" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">API(auth=...)</span></code> applies auth helpers to routes by default. Routes can opt out
with <code class="docutils literal notranslate"><span class="pre">auth=None</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">ScopedAuth</span></code> and <code class="docutils literal notranslate"><span class="pre">auth.requires(...)</span></code> add lightweight scope/role checks on top
of existing auth helpers, returning <code class="docutils literal notranslate"><span class="pre">403</span></code> when the principal lacks a required
scope and documenting scoped OpenAPI security requirements.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">dependencies=[Depends(...)]</span></code> on route decorators runs dependency-graph
dependencies before the handler without injecting an unused return value.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">responder[server]</span></code> keeps Granian as an optional production ASGI dependency.
<code class="docutils literal notranslate"><span class="pre">uvicorn</span></code> remains in the default install and is still used by
<code class="docutils literal notranslate"><span class="pre">api.run()</span></code> unless <code class="docutils literal notranslate"><span class="pre">server=&quot;granian&quot;</span></code> is requested.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">api.run(server=&quot;granian&quot;)</span></code> runs the current app with Granian’s embedded ASGI
server when <code class="docutils literal notranslate"><span class="pre">responder[server]</span></code> is installed, and raises a targeted install
error when it is missing.</p></li>
<li><p>Route dispatch ordering for before hooks, auth, dependency-guards, handler,
and after hooks is now part of the documented v7 behavior.</p></li>
<li><p>A v7 migration guide covering default error responses, auth inheritance,
route dependency guards, removed request-model compatibility, and the server
extra.</p></li>
</ul>
</section>
<section id="id50">
<h3>Changed<a class="headerlink" href="#id50" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Framework-generated errors now use <code class="docutils literal notranslate"><span class="pre">application/problem+json</span></code> by default.
<code class="docutils literal notranslate"><span class="pre">errors</span></code> remains an extension member when present (for example on 422s),
so migration is media-type oriented instead of response-shape oriented.
Pass <code class="docutils literal notranslate"><span class="pre">problem_details=False</span></code> to keep the legacy JSON/plain-text negotiation.</p></li>
<li><p>Problem-details responses are serialized as JSON bytes regardless of the
request’s <code class="docutils literal notranslate"><span class="pre">Accept</span></code> header, and unhandled 500s use the same problem-details
contract by default.</p></li>
<li><p>Explicit <code class="docutils literal notranslate"><span class="pre">Depends(...)</span></code> parameters and registered dependencies take
precedence over auth principal-name injection when they use the same handler
parameter name; the authenticated principal remains available on request
state.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">req.method</span></code> now returns an exact <code class="docutils literal notranslate"><span class="pre">str</span></code>; the no-op exported <code class="docutils literal notranslate"><span class="pre">HTTPMethod</span></code>
subclass has been removed.</p></li>
<li><p>Python 3.11 is now the minimum supported Python version; internal datetime
handling uses the stdlib <code class="docutils literal notranslate"><span class="pre">datetime.UTC</span></code> alias accordingly.</p></li>
</ul>
</section>
<section id="id51">
<h3>Removed<a class="headerlink" href="#id51" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>The deprecated <code class="docutils literal notranslate"><span class="pre">request_model=</span></code> route option and <code class="docutils literal notranslate"><span class="pre">req.state.validated</span></code>
compatibility path have been removed. Use required Pydantic-typed handler
parameters for request-body validation.</p></li>
<li><p>The deprecated private <code class="docutils literal notranslate"><span class="pre">_resolve_dependency</span></code> route helper has been removed;
the request dependency graph is resolved through the shared resolver.</p></li>
</ul>
</section>
<section id="id52">
<h3>Fixed<a class="headerlink" href="#id52" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Byte-range requests now cap the number of requested ranges and coalesce
overlapping or adjacent ranges before building single or multipart responses.</p></li>
<li><p>Request-scoped dependency caching now distinguishes bound methods by
instance, avoiding cross-instance value reuse.</p></li>
<li><p>WebSocket routes now resolve inline <code class="docutils literal notranslate"><span class="pre">Depends(...)</span></code> parameters and run
route-local <code class="docutils literal notranslate"><span class="pre">after=</span></code> hooks.</p></li>
<li><p>Exceptions raised by after hooks now produce a controlled 500 response using
the normal error contract.</p></li>
<li><p>OpenAPI schemas now default missing API metadata to valid string values
instead of emitting <code class="docutils literal notranslate"><span class="pre">null</span></code> for required <code class="docutils literal notranslate"><span class="pre">info</span></code> fields.</p></li>
</ul>
</section>
</section>
<section id="v6-6-1-2026-06-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v6.6.0..v6.6.1">v6.6.1</a> - 2026-06-29<a class="headerlink" href="#v6-6-1-2026-06-29" title="Link to this heading"></a></h2>
<p>A small follow-up release focused on problem-details consistency, packaging
metadata, documentation, and internal route-dispatch maintainability.</p>
<section id="id53">
<h3>Changed<a class="headerlink" href="#id53" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">problem_details=True</span></code> now also applies to production response-model
validation failures, returning <code class="docutils literal notranslate"><span class="pre">application/problem+json</span></code> for those
framework-generated <code class="docutils literal notranslate"><span class="pre">500</span></code> responses.</p></li>
<li><p>Refactored HTTP route dispatch internals into smaller helpers without changing
public behavior.</p></li>
<li><p>Updated project license metadata to the modern SPDX form used by current
packaging tools.</p></li>
<li><p>Refreshed the README with concise examples for route-local hooks, local
dependencies, route-level auth, file-upload saving, and problem-details
responses.</p></li>
</ul>
</section>
</section>
<section id="v6-6-0-2026-06-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v6.5.3..v6.6.0">v6.6.0</a> - 2026-06-29<a class="headerlink" href="#v6-6-0-2026-06-29" title="Link to this heading"></a></h2>
<p>A backward-compatible release that adds route-local controls, explicit local
dependencies, problem-details errors, upload saving, and multipart byte ranges.</p>
<section id="id54">
<h3>Added<a class="headerlink" href="#id54" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong>Route-local hooks</strong> with <code class="docutils literal notranslate"><span class="pre">before=</span></code> and <code class="docutils literal notranslate"><span class="pre">after=</span></code> on <code class="docutils literal notranslate"><span class="pre">api.route()</span></code> and verb
decorators. Global hooks still run, while route-local hooks apply only to the
decorated endpoint.</p></li>
<li><p><strong>Route-level auth enforcement</strong> with <code class="docutils literal notranslate"><span class="pre">auth=</span></code>. Auth helpers such as
<code class="docutils literal notranslate"><span class="pre">BearerAuth</span></code> now enforce access, register their OpenAPI security scheme when
OpenAPI is enabled, and inject the authenticated principal into <code class="docutils literal notranslate"><span class="pre">user</span></code>,
<code class="docutils literal notranslate"><span class="pre">principal</span></code>, or <code class="docutils literal notranslate"><span class="pre">auth</span></code> handler parameters.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">Depends(...)</span></code></strong> for explicit per-route dependency providers without app-wide
registration. Providers can be sync, async, generator, or async-generator
callables and can receive the current request or registered dependencies.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">problem_details=True</span></code></strong> on <code class="docutils literal notranslate"><span class="pre">API(...)</span></code> for RFC 9457-style framework errors
using <code class="docutils literal notranslate"><span class="pre">application/problem+json</span></code>.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">upload.save(path)</span></code></strong> on injected/uploaded <code class="docutils literal notranslate"><span class="pre">UploadFile</span></code> objects, with
streaming writes and optional parent-directory creation.</p></li>
<li><p><strong>Multipart byte-range responses</strong> for <code class="docutils literal notranslate"><span class="pre">resp.file()</span></code> and <code class="docutils literal notranslate"><span class="pre">resp.stream_file()</span></code>
when clients request multiple ranges.</p></li>
</ul>
</section>
<section id="id55">
<h3>Changed<a class="headerlink" href="#id55" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Response format encoders now respect an explicit <code class="docutils literal notranslate"><span class="pre">Content-Type</span></code> already set on
the response instead of overwriting it during serialization.</p></li>
</ul>
</section>
</section>
<section id="v6-5-3-2026-06-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v6.5.2..v6.5.3">v6.5.3</a> - 2026-06-29<a class="headerlink" href="#v6-5-3-2026-06-29" title="Link to this heading"></a></h2>
<section id="id56">
<h3>Fixed<a class="headerlink" href="#id56" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Generated <strong>TypeScript</strong> clients now type-check under <code class="docutils literal notranslate"><span class="pre">tsc</span></code> / <code class="docutils literal notranslate"><span class="pre">deno</span> <span class="pre">check</span></code>.
The opt-in <code class="docutils literal notranslate"><span class="pre">validate</span></code> helpers added in 6.5.2 emitted untyped parameters
(implicit <code class="docutils literal notranslate"><span class="pre">any</span></code>) in the shared JS/TS validation code; the TypeScript output is
now annotated. JavaScript output is unchanged.</p></li>
</ul>
</section>
</section>
<section id="v6-5-2-2026-06-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v6.5.1..v6.5.2">v6.5.2</a> - 2026-06-29<a class="headerlink" href="#v6-5-2-2026-06-29" title="Link to this heading"></a></h2>
<p>A backward-compatible follow-up adding opt-in generated-client validation.</p>
<section id="id57">
<h3>Added<a class="headerlink" href="#id57" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Generated Python, JavaScript, and TypeScript clients now support opt-in
runtime schema validation with <code class="docutils literal notranslate"><span class="pre">validate=True</span></code> / <code class="docutils literal notranslate"><span class="pre">validate:</span> <span class="pre">true</span></code>, raising
<code class="docutils literal notranslate"><span class="pre">APIValidationError</span></code> when outgoing JSON bodies or successful JSON responses do
not match the generated OpenAPI schemas.</p></li>
</ul>
</section>
</section>
<section id="v6-5-1-2026-06-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v6.5.0..v6.5.1">v6.5.1</a> - 2026-06-29<a class="headerlink" href="#v6-5-1-2026-06-29" title="Link to this heading"></a></h2>
<p>A backward-compatible follow-up that rounds out the client generator.</p>
<section id="id58">
<h3>Added<a class="headerlink" href="#id58" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong><code class="docutils literal notranslate"><span class="pre">responder</span> <span class="pre">client</span> <span class="pre">&lt;target&gt;</span></code></strong> CLI subcommand generates a client from the
same import target as <code class="docutils literal notranslate"><span class="pre">responder</span> <span class="pre">run</span></code> — <code class="docutils literal notranslate"><span class="pre">--lang</span></code>, <code class="docutils literal notranslate"><span class="pre">--class-name</span></code>, and
<code class="docutils literal notranslate"><span class="pre">--output</span></code>/<code class="docutils literal notranslate"><span class="pre">-o</span></code> select the language, class name, and destination (stdout by
default).</p></li>
<li><p>Generated <strong>Python clients emit <code class="docutils literal notranslate"><span class="pre">TypedDict</span></code> definitions</strong> and <strong>TypeScript
clients exported interfaces</strong> for OpenAPI component schemas, used for the
request-body and success-response method signatures.</p></li>
</ul>
</section>
</section>
<section id="v6-5-0-2026-06-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v6.4.0..v6.5.0">v6.5.0</a> - 2026-06-29<a class="headerlink" href="#v6-5-0-2026-06-29" title="Link to this heading"></a></h2>
<p>A backward-compatible release adding first-class client generation.</p>
<section id="id59">
<h3>Added<a class="headerlink" href="#id59" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong><code class="docutils literal notranslate"><span class="pre">responder.ext.clientgen</span></code></strong> generates small Python, JavaScript,
TypeScript, Ruby, and PHP clients from Responder’s OpenAPI schema.
<code class="docutils literal notranslate"><span class="pre">generate_client(...)</span></code> returns source code, and <code class="docutils literal notranslate"><span class="pre">write_client(...)</span></code> writes a
module to disk.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">API.generate_client(...)</span></code></strong> is the app-level convenience wrapper:
<code class="docutils literal notranslate"><span class="pre">api.generate_client(class_name=&quot;ServiceClient&quot;)</span></code> returns source, while
<code class="docutils literal notranslate"><span class="pre">api.generate_client(&quot;clients/service.py&quot;,</span> <span class="pre">class_name=&quot;ServiceClient&quot;)</span></code> writes
a ready-to-import client module. Pass <code class="docutils literal notranslate"><span class="pre">language=&quot;typescript&quot;</span></code> (or
<code class="docutils literal notranslate"><span class="pre">javascript</span></code>, <code class="docutils literal notranslate"><span class="pre">ruby</span></code>, <code class="docutils literal notranslate"><span class="pre">php</span></code>, <code class="docutils literal notranslate"><span class="pre">python</span></code>) to select the target.</p></li>
<li><p>Generated clients include method signatures from path/query parameters, JSON
request bodies, bearer/basic/API-key header helpers, structured <code class="docutils literal notranslate"><span class="pre">APIError</span></code>,
real HTTP transport, typed Python/TypeScript signatures where schema permits,
and a Python <code class="docutils literal notranslate"><span class="pre">session=</span></code> hook so the same generated client can call
<code class="docutils literal notranslate"><span class="pre">api.requests</span></code> in tests.</p></li>
</ul>
</section>
</section>
<section id="v6-4-0-2026-06-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v6.3.1..v6.4.0">v6.4.0</a> - 2026-06-29<a class="headerlink" href="#v6-4-0-2026-06-29" title="Link to this heading"></a></h2>
<p>A backward-compatible release that makes typed path parameters and resumable
downloads much sharper in practice.</p>
<section id="id60">
<h3>Added<a class="headerlink" href="#id60" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong>Typed path parameters now work even on plain route segments.</strong> A route like
<code class="docutils literal notranslate"><span class="pre">/users/{id}</span></code> can now declare <code class="docutils literal notranslate"><span class="pre">id:</span> <span class="pre">int</span></code> (or <code class="docutils literal notranslate"><span class="pre">UUID</span></code>, etc.) and Responder
validates/coerces the path value into that type, returning a <code class="docutils literal notranslate"><span class="pre">422</span></code> on bad
input instead of passing a raw string through. WebSocket routes get the same
coercion and close invalid typed path parameters with <code class="docutils literal notranslate"><span class="pre">1008</span></code>.</p></li>
<li><p><strong>Path-parameter OpenAPI got smarter.</strong> The generated schema now reflects:</p>
<ul>
<li><p>a bare handler annotation on a plain <code class="docutils literal notranslate"><span class="pre">{id}</span></code> segment,</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Path(...)</span></code> aliases/constraints/description metadata, and</p></li>
<li><p>the built-in <code class="docutils literal notranslate"><span class="pre">{id:uuid}</span></code> convertor as <code class="docutils literal notranslate"><span class="pre">{type:</span> <span class="pre">string,</span> <span class="pre">format:</span> <span class="pre">uuid}</span></code>.
Class-based views now generate method-specific parameters from <code class="docutils literal notranslate"><span class="pre">on_get</span></code> /
<code class="docutils literal notranslate"><span class="pre">on_post</span></code> / etc., so one method’s query parameters no longer disappear from
the schema.</p></li>
</ul>
</li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">If-Range</span></code> support for file responses.</strong> <code class="docutils literal notranslate"><span class="pre">resp.file()</span></code>,
<code class="docutils literal notranslate"><span class="pre">resp.stream_file()</span></code>, and <code class="docutils literal notranslate"><span class="pre">resp.download()</span></code> now honor <code class="docutils literal notranslate"><span class="pre">If-Range</span></code> so a
stale resumable-download request automatically falls back to the full body
instead of returning a partial response for the wrong representation.</p></li>
</ul>
</section>
</section>
<section id="v6-3-1-2026-06-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v6.3.0..v6.3.1">v6.3.1</a> - 2026-06-29<a class="headerlink" href="#v6-3-1-2026-06-29" title="Link to this heading"></a></h2>
<section id="id61">
<h3>Fixed<a class="headerlink" href="#id61" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>OpenAPI now emits query/header/cookie/path parameters at the <strong>operation</strong>
level rather than the path-item level. The path-item placement (present since
the typed-OpenAPI feature in 5.0) leaked a route’s parameters onto sibling
methods sharing the same path — e.g. a <code class="docutils literal notranslate"><span class="pre">&#64;api.post</span></code> inherited a <code class="docutils literal notranslate"><span class="pre">&#64;api.get</span></code>’s
query parameters. Each operation now carries only its own parameters (also the
placement most tooling and codegen expect).</p></li>
</ul>
</section>
</section>
<section id="v6-3-0-2026-06-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v6.2.0..v6.3.0">v6.3.0</a> - 2026-06-29<a class="headerlink" href="#v6-3-0-2026-06-29" title="Link to this heading"></a></h2>
<p>A backward-compatible release adding sorting &amp; filtering helpers that complete
the list-endpoint story alongside pagination.</p>
<section id="id62">
<h3>Added<a class="headerlink" href="#id62" title="Link to this heading"></a></h3>
<ul>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">responder.ext.query</span></code></strong> — in-memory helpers for list endpoints (dicts or
objects, no ORM coupling):</p>
<ul class="simple">
<li><p><strong><code class="docutils literal notranslate"><span class="pre">sort_items(items,</span> <span class="pre">spec,</span> <span class="pre">*,</span> <span class="pre">allowed=None)</span></code></strong> sorts by a <code class="docutils literal notranslate"><span class="pre">name,-created</span></code>
spec (<code class="docutils literal notranslate"><span class="pre">-</span></code> = descending, multiple keys, <code class="docutils literal notranslate"><span class="pre">None</span></code> sorts last). Pass
<code class="docutils literal notranslate"><span class="pre">allowed=</span></code> for a client-supplied sort so users can’t order by arbitrary
attributes — an out-of-list (or incomparable) field returns <code class="docutils literal notranslate"><span class="pre">400</span></code>.
<code class="docutils literal notranslate"><span class="pre">parse_sort</span></code> is exposed for sorting in the database yourself.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">filter_items(items,</span> <span class="pre">filters)</span></code></strong> applies <code class="docutils literal notranslate"><span class="pre">field</span> <span class="pre">==</span> <span class="pre">value</span></code> equality and
skips <code class="docutils literal notranslate"><span class="pre">None</span></code> values, so optional <code class="docutils literal notranslate"><span class="pre">Query</span></code> markers pass straight through.</p></li>
</ul>
<p>Together with <code class="docutils literal notranslate"><span class="pre">Query</span></code> markers and <code class="docutils literal notranslate"><span class="pre">responder.ext.pagination</span></code> they make a
complete filter → sort → paginate pipeline.</p>
</li>
</ul>
</section>
</section>
<section id="v6-2-0-2026-06-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v6.1.0..v6.2.0">v6.2.0</a> - 2026-06-29<a class="headerlink" href="#v6-2-0-2026-06-29" title="Link to this heading"></a></h2>
<p>A backward-compatible release adding pagination helpers for list endpoints.</p>
<section id="id63">
<h3>Added<a class="headerlink" href="#id63" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong><code class="docutils literal notranslate"><span class="pre">responder.ext.pagination</span></code></strong> — a generic <code class="docutils literal notranslate"><span class="pre">Page[T]</span></code> response envelope
(<code class="docutils literal notranslate"><span class="pre">items</span></code>, <code class="docutils literal notranslate"><span class="pre">total</span></code>, <code class="docutils literal notranslate"><span class="pre">page</span></code>, <code class="docutils literal notranslate"><span class="pre">size</span></code>, <code class="docutils literal notranslate"><span class="pre">pages</span></code>) and a <code class="docutils literal notranslate"><span class="pre">paginate(items,</span> <span class="pre">*,</span> <span class="pre">page,</span> <span class="pre">size,</span> <span class="pre">total=None)</span></code> helper. <code class="docutils literal notranslate"><span class="pre">paginate</span></code> slices an in-memory collection by
default, or wraps an already-sliced page when you pass <code class="docutils literal notranslate"><span class="pre">total=</span></code> (e.g. a
<code class="docutils literal notranslate"><span class="pre">LIMIT/OFFSET</span></code> query). Pairs with the typed <code class="docutils literal notranslate"><span class="pre">Query</span></code> markers and
<code class="docutils literal notranslate"><span class="pre">response_model=Page[Item]</span></code> — the OpenAPI schema documents the envelope inline,
referencing your element model.</p></li>
<li><p>Parametrized generic models (e.g. <code class="docutils literal notranslate"><span class="pre">Page[Item]</span></code>) are now emitted <strong>inline</strong> in
OpenAPI (referencing their element components) rather than registered under a
bracketed — and spec-invalid — component name.</p></li>
</ul>
</section>
</section>
<section id="v6-1-0-2026-06-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v6.0.2..v6.1.0">v6.1.0</a> - 2026-06-29<a class="headerlink" href="#v6-1-0-2026-06-29" title="Link to this heading"></a></h2>
<p>A backward-compatible release that makes Server-Sent Events production-grade.</p>
<section id="id64">
<h3>Added<a class="headerlink" href="#id64" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong>Production-grade <code class="docutils literal notranslate"><span class="pre">resp.sse</span></code>.</strong> Server-Sent Events gain:</p>
<ul>
<li><p><strong>JSON-encoded data</strong> — a <code class="docutils literal notranslate"><span class="pre">data</span></code> value that is a <code class="docutils literal notranslate"><span class="pre">dict</span></code>/<code class="docutils literal notranslate"><span class="pre">list</span></code> is
serialized automatically (great for structured/LLM streaming).</p></li>
<li><p><strong>Comment frames</strong> via <code class="docutils literal notranslate"><span class="pre">{&quot;comment&quot;:</span> <span class="pre">&quot;...&quot;}</span></code> (and raw <code class="docutils literal notranslate"><span class="pre">bytes</span></code> pass
through verbatim).</p></li>
<li><p><strong>Opt-in heartbeat</strong> — <code class="docutils literal notranslate"><span class="pre">&#64;resp.sse(heartbeat=15)</span></code> emits a keepalive comment
during idle periods (without interrupting the producer mid-event), so
long-lived streams survive proxy idle-timeouts.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">X-Accel-Buffering:</span> <span class="pre">no</span></code></strong> so events flush immediately behind nginx and
similar proxies.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">&#64;resp.sse(heartbeat=...)</span></code> decorator-with-arguments form.</p></li>
</ul>
</li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">req.last_event_id</span></code></strong> exposes the SSE <code class="docutils literal notranslate"><span class="pre">Last-Event-ID</span></code> request header, so a
handler can resume a stream where a reconnecting client left off.</p></li>
</ul>
</section>
</section>
<section id="v6-0-2-2026-06-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v6.0.1..v6.0.2">v6.0.2</a> - 2026-06-29<a class="headerlink" href="#v6-0-2-2026-06-29" title="Link to this heading"></a></h2>
<p>A bugfix release closing a set of cross-feature interaction defects found by an
adversarial review of the 5.1-&gt;6.0 work — including two remotely-triggerable
500s and a bypass of <code class="docutils literal notranslate"><span class="pre">max_request_size</span></code> on multipart uploads. Upgrading from
6.0.x is strongly recommended.</p>
<section id="id65">
<h3>Fixed<a class="headerlink" href="#id65" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong>Remote 500 on file endpoints.</strong> An <code class="docutils literal notranslate"><span class="pre">If-Modified-Since</span></code> header with a <code class="docutils literal notranslate"><span class="pre">-0000</span></code>
timezone crashed every conditional file response (a naive-vs-aware datetime
comparison sat outside the try/except). Both sides are now normalized to UTC.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">max_request_size</span></code> bypass + “Stream consumed” 500 on multipart.</strong> Parsing a
form/file body (<code class="docutils literal notranslate"><span class="pre">Form()</span></code>/<code class="docutils literal notranslate"><span class="pre">File()</span></code> markers or <code class="docutils literal notranslate"><span class="pre">req.media(&quot;files&quot;)</span></code>) now buffers
through the size-checked body, so the cap is enforced (<code class="docutils literal notranslate"><span class="pre">413</span></code>) and the body
stays readable afterward (<code class="docutils literal notranslate"><span class="pre">req.content</span></code>, <code class="docutils literal notranslate"><span class="pre">media(&quot;form&quot;)</span></code>, …) in any order.
(This trades 5.5’s spool-to-disk streaming for correctness; for true streaming
uploads, read <code class="docutils literal notranslate"><span class="pre">req.stream()</span></code> directly.)</p></li>
<li><p><strong>Recursive Pydantic models</strong> registered an empty self-referential OpenAPI
component; the real schema body is now emitted.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">APIKeyAuth(location=&quot;query&quot;)</span></code></strong> crashed on WebSocket routes (it read
<code class="docutils literal notranslate"><span class="pre">.params</span></code>, which a Starlette WebSocket lacks); it now falls back to
<code class="docutils literal notranslate"><span class="pre">.query_params</span></code>.</p></li>
<li><p><strong>Callable-instance generator dependencies</strong> (a class whose <code class="docutils literal notranslate"><span class="pre">__call__</span></code> yields)
now run their teardown instead of leaking the generator object as the value.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">dependency_overrides</span></code></strong> now reaches into the app-scoped graph: overriding a
dependency that an <code class="docutils literal notranslate"><span class="pre">app</span></code>-scoped dependency depends on resolves correctly (was a
<code class="docutils literal notranslate"><span class="pre">DependencyScopeError</span></code> / stale cached value), and overrides restore per-key so
nested blocks don’t clobber each other.</p></li>
<li><p><strong>Conditional responses.</strong> A <code class="docutils literal notranslate"><span class="pre">304</span></code> now carries the negotiated <code class="docutils literal notranslate"><span class="pre">Vary</span></code> header,
and a <code class="docutils literal notranslate"><span class="pre">Range</span></code> request with a matching validator returns <code class="docutils literal notranslate"><span class="pre">304</span></code> rather than a
<code class="docutils literal notranslate"><span class="pre">206</span></code> body.</p></li>
<li><p>OpenAPI now logs a warning on a component <strong>name collision</strong> (two distinct
models sharing a <code class="docutils literal notranslate"><span class="pre">__name__</span></code>) instead of silently serving one for both.</p></li>
</ul>
</section>
</section>
<section id="v6-0-1-2026-06-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v6.0.0..v6.0.1">v6.0.1</a> - 2026-06-29<a class="headerlink" href="#v6-0-1-2026-06-29" title="Link to this heading"></a></h2>
<section id="id66">
<h3>Fixed<a class="headerlink" href="#id66" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong><code class="docutils literal notranslate"><span class="pre">Annotated[...]</span></code> markers with a <code class="docutils literal notranslate"><span class="pre">None</span></code> default</strong> (e.g.
<code class="docutils literal notranslate"><span class="pre">token:</span> <span class="pre">Annotated[str,</span> <span class="pre">Header(None)]</span> <span class="pre">=</span> <span class="pre">None</span></code>) were not detected on Python
3.10, where <code class="docutils literal notranslate"><span class="pre">get_type_hints</span></code> implicitly wraps the annotation in <code class="docutils literal notranslate"><span class="pre">Optional</span></code> —
the marker is now found through the <code class="docutils literal notranslate"><span class="pre">Union</span></code>. (Latent since 5.3.)</p></li>
</ul>
</section>
</section>
<section id="v6-0-0-2026-06-28">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v5.6.0..v6.0.0">v6.0.0</a> - 2026-06-28<a class="headerlink" href="#v6-0-0-2026-06-28" title="Link to this heading"></a></h2>
<p>A small, deliberate major release: <strong>no new features</strong> — it removes the
deprecation shims introduced during 5.x and flips a few defaults to the
more-correct behavior. Every change was announced with a <code class="docutils literal notranslate"><span class="pre">DeprecationWarning</span></code>
or an opt-in knob during 5.x, so code that runs clean under
<code class="docutils literal notranslate"><span class="pre">-W</span> <span class="pre">error::DeprecationWarning</span></code> on 5.6 upgrades without surprises. See the
<a class="reference external" href="https://github.com/kennethreitz/responder/blob/main/docs/migration-v6.md">v6 migration guide</a>.</p>
<section id="id67">
<h3>Removed<a class="headerlink" href="#id67" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong>The case-insensitive <code class="docutils literal notranslate"><span class="pre">req.method</span></code> comparison shim.</strong> <code class="docutils literal notranslate"><span class="pre">req.method</span></code> is now a
plain uppercase <code class="docutils literal notranslate"><span class="pre">str</span></code>; compare against uppercase literals (<code class="docutils literal notranslate"><span class="pre">req.method</span> <span class="pre">==</span> <span class="pre">&quot;GET&quot;</span></code>). (Announced in 5.0.)</p></li>
<li><p><strong>The single-unnamed-parameter dependency-provider shim.</strong> A provider’s
request parameter must be named <code class="docutils literal notranslate"><span class="pre">req</span></code>/<code class="docutils literal notranslate"><span class="pre">request</span></code> or annotated <code class="docutils literal notranslate"><span class="pre">Request</span></code>;
otherwise resolution raises <code class="docutils literal notranslate"><span class="pre">DependencyResolutionError</span></code>. (Announced in 5.0.)</p></li>
</ul>
</section>
<section id="id68">
<h3>Changed<a class="headerlink" href="#id68" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong><code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">req.media(&quot;files&quot;)</span></code></strong> returns streaming <code class="docutils literal notranslate"><span class="pre">UploadFile</span></code> objects keyed by
field name instead of a fully-buffered bytes-dict; <code class="docutils literal notranslate"><span class="pre">File()</span></code> markers are the
typed equivalent. (Deprecated in 5.6.)</p></li>
<li><p><strong>JSON defaults to <code class="docutils literal notranslate"><span class="pre">ensure_ascii=False</span></code></strong> (raw UTF-8). This changes response
bytes and <code class="docutils literal notranslate"><span class="pre">auto_etag</span></code> values for non-ASCII payloads; pass
<code class="docutils literal notranslate"><span class="pre">API(json_ensure_ascii=True)</span></code> to restore <code class="docutils literal notranslate"><span class="pre">\uXXXX</span></code> escaping. (Knob added in 5.6.)</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">Vary:</span> <span class="pre">Accept</span></code></strong> is now sent by default on content-negotiated responses
(correct for shared caches); pass <code class="docutils literal notranslate"><span class="pre">API(auto_vary=False)</span></code> to opt out. (Opt-in
added in 5.1.)</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">Route.__hash__</span></code></strong> no longer includes <code class="docutils literal notranslate"><span class="pre">before_request</span></code>, so routes that
compare equal now hash equal.</p></li>
</ul>
</section>
</section>
<section id="v5-6-0-2026-06-28">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v5.5.0..v5.6.0">v5.6.0</a> - 2026-06-28<a class="headerlink" href="#v5-6-0-2026-06-28" title="Link to this heading"></a></h2>
<p>A backward-compatible release that stages the breaking changes coming in
Responder 6.0 — adding the opt-in knobs and deprecation warnings so you can
adapt on 5.x first. See the <a class="reference external" href="https://github.com/kennethreitz/responder/blob/main/docs/migration-v6.md">v6 migration guide</a>.</p>
<section id="id69">
<h3>Added<a class="headerlink" href="#id69" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong><code class="docutils literal notranslate"><span class="pre">API(json_ensure_ascii=...)</span></code></strong> controls JSON non-ASCII escaping. The default
stays <code class="docutils literal notranslate"><span class="pre">True</span></code> (escape as <code class="docutils literal notranslate"><span class="pre">\uXXXX</span></code>) in 5.x and flips to <code class="docutils literal notranslate"><span class="pre">False</span></code> (raw UTF-8) in
6.0; set it explicitly to lock in either behavior.</p></li>
</ul>
</section>
<section id="id70">
<h3>Deprecated<a class="headerlink" href="#id70" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong><code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">req.media(&quot;files&quot;)</span></code></strong> (the fully-buffered bytes-dict) now emits a
<code class="docutils literal notranslate"><span class="pre">DeprecationWarning</span></code>. In 6.0 it returns streaming <code class="docutils literal notranslate"><span class="pre">UploadFile</span></code> objects; use
<code class="docutils literal notranslate"><span class="pre">File()</span></code> markers for the new API today. The bytes-dict is still returned in
5.x.</p></li>
<li><p>Documented the project’s <strong>deprecation policy</strong> and the full 6.0 breaking-change
list in <code class="docutils literal notranslate"><span class="pre">docs/migration-v6.md</span></code>.</p></li>
</ul>
</section>
</section>
<section id="v5-5-0-2026-06-28">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v5.4.0..v5.5.0">v5.5.0</a> - 2026-06-28<a class="headerlink" href="#v5-5-0-2026-06-28" title="Link to this heading"></a></h2>
<p>A backward-compatible release adding type-driven file uploads and form fields,
completing the typed-parameter surface. No existing call signatures change.</p>
<section id="id71">
<h3>Added<a class="headerlink" href="#id71" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong><code class="docutils literal notranslate"><span class="pre">File()</span></code> and <code class="docutils literal notranslate"><span class="pre">Form()</span></code> markers.</strong> <code class="docutils literal notranslate"><span class="pre">File()</span></code> injects an uploaded file as an
<code class="docutils literal notranslate"><span class="pre">UploadFile</span></code> (read with <code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">f.read()</span></code>, or stream it in chunks — large
uploads are spooled to disk by Starlette’s parser rather than held in
memory); <code class="docutils literal notranslate"><span class="pre">Form()</span></code> injects a form field (urlencoded or multipart), coerced and
validated like <code class="docutils literal notranslate"><span class="pre">Query()</span></code>. A sequence annotation (<code class="docutils literal notranslate"><span class="pre">list[UploadFile]</span></code>,
<code class="docutils literal notranslate"><span class="pre">list[str]</span></code>) collects repeated fields. Both support the <code class="docutils literal notranslate"><span class="pre">Annotated[...]</span></code> form.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">responder.UploadFile</span></code></strong> is exported for annotating upload parameters.</p></li>
<li><p><strong>Multipart OpenAPI.</strong> Routes with <code class="docutils literal notranslate"><span class="pre">File()</span></code>/<code class="docutils literal notranslate"><span class="pre">Form()</span></code> markers generate a
<code class="docutils literal notranslate"><span class="pre">multipart/form-data</span></code> (or <code class="docutils literal notranslate"><span class="pre">application/x-www-form-urlencoded</span></code>) request body —
files as <code class="docutils literal notranslate"><span class="pre">{type:</span> <span class="pre">string,</span> <span class="pre">format:</span> <span class="pre">binary}</span></code> — so the interactive docs show a
file picker.</p></li>
</ul>
<p>The existing <code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">req.media(&quot;files&quot;)</span></code> bytes-dict contract is unchanged.</p>
</section>
</section>
<section id="v5-4-0-2026-06-28">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v5.3.0..v5.4.0">v5.4.0</a> - 2026-06-28<a class="headerlink" href="#v5-4-0-2026-06-28" title="Link to this heading"></a></h2>
<p>A backward-compatible release focused on testing, operations, and HTTP
correctness. No existing call signatures change.</p>
<section id="id72">
<h3>Added<a class="headerlink" href="#id72" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong><code class="docutils literal notranslate"><span class="pre">api.dependency_overrides(**overrides)</span></code></strong> — a context manager that swaps
dependencies for tests and restores them on exit. Values may be bare objects
(wrapped automatically) or provider callables (which still receive
sub-dependencies and the request). Overrides are request-scoped, so they
replace and bypass the cache of an <code class="docutils literal notranslate"><span class="pre">app</span></code>-scoped dependency too.</p></li>
<li><p><strong>Health checks.</strong> <code class="docutils literal notranslate"><span class="pre">api.add_health_check(name,</span> <span class="pre">check)</span></code> registers a readiness
check (sync or async; passes unless it returns <code class="docutils literal notranslate"><span class="pre">False</span></code> or raises) and
<code class="docutils literal notranslate"><span class="pre">API(health_route=&quot;/health&quot;)</span></code> serves the aggregate — <code class="docutils literal notranslate"><span class="pre">200</span></code> with per-check
JSON when all pass, <code class="docutils literal notranslate"><span class="pre">503</span></code> otherwise. The route is excluded from the OpenAPI
schema.</p></li>
<li><p><strong>Named routes.</strong> <code class="docutils literal notranslate"><span class="pre">&#64;api.route(...,</span> <span class="pre">name=&quot;...&quot;)</span></code> (and the verb decorators /
<code class="docutils literal notranslate"><span class="pre">add_route</span></code>) name a route so <code class="docutils literal notranslate"><span class="pre">api.url_for(&quot;name&quot;,</span> <span class="pre">**params)</span></code> can reverse it by
string — decoupling URL generation from the endpoint’s function identity
(so lambdas and shared names are addressable). Works for WebSocket routes too.</p></li>
</ul>
</section>
<section id="id73">
<h3>Fixed<a class="headerlink" href="#id73" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong>Conditional requests for served files.</strong> <code class="docutils literal notranslate"><span class="pre">resp.file()</span></code>, <code class="docutils literal notranslate"><span class="pre">resp.stream_file()</span></code>,
and <code class="docutils literal notranslate"><span class="pre">resp.download()</span></code> now set a stat-based weak <code class="docutils literal notranslate"><span class="pre">ETag</span></code> and <code class="docutils literal notranslate"><span class="pre">Last-Modified</span></code> by
default, so <code class="docutils literal notranslate"><span class="pre">If-None-Match</span></code> / <code class="docutils literal notranslate"><span class="pre">If-Modified-Since</span></code> get a <code class="docutils literal notranslate"><span class="pre">304</span></code> (and <code class="docutils literal notranslate"><span class="pre">file()</span></code>
no longer reads the whole file to hash it under <code class="docutils literal notranslate"><span class="pre">auto_etag</span></code>). Range requests
are unaffected. Pass <code class="docutils literal notranslate"><span class="pre">conditional=False</span></code> to opt out.</p></li>
</ul>
</section>
</section>
<section id="v5-3-0-2026-06-28">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v5.2.0..v5.3.0">v5.3.0</a> - 2026-06-28<a class="headerlink" href="#v5-3-0-2026-06-28" title="Link to this heading"></a></h2>
<p>A backward-compatible release that finishes the type-driven I/O and OpenAPI
authoring story: <code class="docutils literal notranslate"><span class="pre">Annotated[]</span></code> markers, generic response models, and
first-class route/operation metadata. No existing call signatures change.</p>
<section id="id74">
<h3>Added<a class="headerlink" href="#id74" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong><code class="docutils literal notranslate"><span class="pre">Annotated[]</span></code> marker form.</strong> <code class="docutils literal notranslate"><span class="pre">Query</span></code>/<code class="docutils literal notranslate"><span class="pre">Header</span></code>/<code class="docutils literal notranslate"><span class="pre">Cookie</span></code>/<code class="docutils literal notranslate"><span class="pre">Path</span></code> markers can
now be written as <code class="docutils literal notranslate"><span class="pre">q:</span> <span class="pre">Annotated[int,</span> <span class="pre">Query(ge=1)]</span></code> (PEP 593), keeping the
parameter’s default value in the usual slot — the FastAPI-familiar style — in
addition to the existing <code class="docutils literal notranslate"><span class="pre">q:</span> <span class="pre">int</span> <span class="pre">=</span> <span class="pre">Query(...)</span></code> form. Constraints, aliases,
and OpenAPI emission work identically either way.</p></li>
<li><p><strong>Generic <code class="docutils literal notranslate"><span class="pre">response_model</span></code>.</strong> <code class="docutils literal notranslate"><span class="pre">response_model=list[Model]</span></code>, tuples, and unions
(<code class="docutils literal notranslate"><span class="pre">Model</span> <span class="pre">|</span> <span class="pre">ErrorModel</span></code>) are now validated and serialized via a <code class="docutils literal notranslate"><span class="pre">TypeAdapter</span></code>
and documented correctly in OpenAPI — an <code class="docutils literal notranslate"><span class="pre">array</span></code> with an <code class="docutils literal notranslate"><span class="pre">items</span></code> <code class="docutils literal notranslate"><span class="pre">$ref</span></code> for a
list, <code class="docutils literal notranslate"><span class="pre">oneOf</span></code>/<code class="docutils literal notranslate"><span class="pre">anyOf</span></code> for a union, with the referenced models hoisted into
<code class="docutils literal notranslate"><span class="pre">components/schemas</span></code>. (<code class="docutils literal notranslate"><span class="pre">response_model=list[Model]</span></code> previously registered a
bogus schema named <code class="docutils literal notranslate"><span class="pre">list</span></code>.) A bare <code class="docutils literal notranslate"><span class="pre">-&gt;</span> <span class="pre">list[Model]</span></code> <em>return annotation</em> still
appears in the schema but stays un-validated at runtime, so existing handlers
returning loose data keep working.</p></li>
<li><p><strong>Route/operation metadata.</strong> <code class="docutils literal notranslate"><span class="pre">tags</span></code>, <code class="docutils literal notranslate"><span class="pre">summary</span></code>, <code class="docutils literal notranslate"><span class="pre">description</span></code>,
<code class="docutils literal notranslate"><span class="pre">operation_id</span></code>, and <code class="docutils literal notranslate"><span class="pre">deprecated</span></code> kwargs on <code class="docutils literal notranslate"><span class="pre">&#64;api.route</span></code> (and the verb
decorators) flow into the generated OpenAPI operation; a docstring-YAML block
still overrides them.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">API(openapi_servers=[...])</span></code></strong> populates the OpenAPI <code class="docutils literal notranslate"><span class="pre">servers</span></code> list.</p></li>
</ul>
</section>
</section>
<section id="v5-2-0-2026-06-28">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v5.1.0..v5.2.0">v5.2.0</a> - 2026-06-28<a class="headerlink" href="#v5-2-0-2026-06-28" title="Link to this heading"></a></h2>
<p>A backward-compatible release that rounds out the security story: a batteries-
included authentication extension that wires straight into OpenAPI (so the
interactive docs get an <strong>Authorize</strong> button), and an opt-in security-headers
middleware. No existing call signatures change.</p>
<section id="id75">
<h3>Added<a class="headerlink" href="#id75" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong><code class="docutils literal notranslate"><span class="pre">responder.ext.auth</span></code></strong> — <code class="docutils literal notranslate"><span class="pre">BearerAuth</span></code>, <code class="docutils literal notranslate"><span class="pre">BasicAuth</span></code>, and <code class="docutils literal notranslate"><span class="pre">APIKeyAuth</span></code>
schemes. Each is a callable that extracts the credential, runs your
(sync or async) <code class="docutils literal notranslate"><span class="pre">verify</span></code> callback, and returns the principal — or raises
<code class="docutils literal notranslate"><span class="pre">401</span></code> with the correct <code class="docutils literal notranslate"><span class="pre">WWW-Authenticate</span></code> challenge. Use one as a dependency
to inject the principal into a handler, or call it directly. For static
secrets, pass them inline (<code class="docutils literal notranslate"><span class="pre">BearerAuth(tokens=[...])</span></code>,
<code class="docutils literal notranslate"><span class="pre">APIKeyAuth(keys=[...])</span></code>, <code class="docutils literal notranslate"><span class="pre">BasicAuth(credentials={...})</span></code>) and the scheme
compares them in constant time.</p></li>
<li><p><strong>OpenAPI security schemes.</strong> <code class="docutils literal notranslate"><span class="pre">api.add_security_scheme(name,</span> <span class="pre">scheme)</span></code> (or
<code class="docutils literal notranslate"><span class="pre">scheme.register(api)</span></code>) populates <code class="docutils literal notranslate"><span class="pre">components.securitySchemes</span></code> so Swagger /
ReDoc render an <strong>Authorize</strong> button. A <code class="docutils literal notranslate"><span class="pre">security=</span></code> kwarg on routes (and the
verb decorators) marks which operations require auth; <code class="docutils literal notranslate"><span class="pre">default=True</span></code> requires
a scheme on every operation.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">API(security_headers=True)</span></code></strong> and <strong><code class="docutils literal notranslate"><span class="pre">responder.middleware.SecurityHeadersMiddleware</span></code></strong>
— add <code class="docutils literal notranslate"><span class="pre">X-Content-Type-Options:</span> <span class="pre">nosniff</span></code>, <code class="docutils literal notranslate"><span class="pre">X-Frame-Options:</span> <span class="pre">DENY</span></code>, and
<code class="docutils literal notranslate"><span class="pre">Referrer-Policy:</span> <span class="pre">strict-origin-when-cross-origin</span></code> to every response (opt-in).
Pass a dict to add a <code class="docutils literal notranslate"><span class="pre">content_security_policy</span></code> / <code class="docutils literal notranslate"><span class="pre">permissions_policy</span></code> or
override any header. Headers a handler set itself are preserved.</p></li>
</ul>
</section>
<section id="id76">
<h3>Changed<a class="headerlink" href="#id76" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Dependency providers may now be <strong>callable instances</strong> with an async
<code class="docutils literal notranslate"><span class="pre">__call__</span></code> (previously only plain async functions were awaited; an async
<code class="docutils literal notranslate"><span class="pre">__call__</span></code> was mistakenly run in a thread). This is what lets an auth scheme
object be used directly as a dependency.</p></li>
</ul>
</section>
</section>
<section id="v5-1-0-2026-06-28">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v5.0.0..v5.1.0">v5.1.0</a> - 2026-06-28<a class="headerlink" href="#v5-1-0-2026-06-28" title="Link to this heading"></a></h2>
<p>A backward-compatible follow-up that finishes what v5 started: it makes the
type-driven OpenAPI and typed-parameter features correct for the common cases
they missed, turns the documented-but-absent HSTS header into a real one, and
adds the small ergonomics the typed surface implies. No existing call
signatures change.</p>
<section id="id77">
<h3>Fixed<a class="headerlink" href="#id77" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong>Type-driven OpenAPI now emits valid documents for nested models.</strong> A model
containing another model previously produced a dangling <code class="docutils literal notranslate"><span class="pre">#/$defs/...</span></code>
reference (the nested schema was never registered as a component), so Swagger
UI / ReDoc / codegen could not resolve it. Each nested model is now hoisted
into its own top-level <code class="docutils literal notranslate"><span class="pre">components/schemas</span></code> entry with rewritten <code class="docutils literal notranslate"><span class="pre">$ref</span></code>s.</p></li>
<li><p><strong>OpenAPI output matches the declared dialect.</strong> Under a <code class="docutils literal notranslate"><span class="pre">3.0.x</span></code> version,
<code class="docutils literal notranslate"><span class="pre">Optional[...]</span></code> fields (which Pydantic v2 emits as <code class="docutils literal notranslate"><span class="pre">anyOf:</span> <span class="pre">[...,</span> <span class="pre">{type:</span> <span class="pre">null}]</span></code>,
invalid in 3.0) are down-converted to <code class="docutils literal notranslate"><span class="pre">nullable</span></code>, and array-valued <code class="docutils literal notranslate"><span class="pre">examples</span></code>
are singularized — so the document validates. <code class="docutils literal notranslate"><span class="pre">3.1</span></code> output is unchanged.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">Query()</span></code>/<code class="docutils literal notranslate"><span class="pre">Header()</span></code>/<code class="docutils literal notranslate"><span class="pre">Cookie()</span></code>/<code class="docutils literal notranslate"><span class="pre">Path()</span></code> markers now enforce their
constraints.</strong> <code class="docutils literal notranslate"><span class="pre">Query(min_length=3)</span></code>, <code class="docutils literal notranslate"><span class="pre">Query(gt=0)</span></code>, etc. were silently
ignored (validation was built from the bare annotation); they now apply and
return <code class="docutils literal notranslate"><span class="pre">422</span></code> on violation, and a typo’d keyword (e.g. <code class="docutils literal notranslate"><span class="pre">Query(dafault=5)</span></code>) now
raises <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> at definition time instead of silently making the parameter
required. A marker’s <code class="docutils literal notranslate"><span class="pre">description</span></code>/<code class="docutils literal notranslate"><span class="pre">deprecated</span></code> now appear in the OpenAPI spec.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">enable_hsts=True</span></code> now sends a real <code class="docutils literal notranslate"><span class="pre">Strict-Transport-Security</span></code> header</strong>
(in addition to the existing HTTP→HTTPS redirect). It previously only
redirected, despite the docs promising browsers “see the HSTS header.”</p></li>
</ul>
</section>
<section id="id78">
<h3>Added<a class="headerlink" href="#id78" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong>HTTP verb shortcut decorators</strong> — <code class="docutils literal notranslate"><span class="pre">&#64;api.get</span></code>, <code class="docutils literal notranslate"><span class="pre">&#64;api.post</span></code>, <code class="docutils literal notranslate"><span class="pre">&#64;api.put</span></code>,
<code class="docutils literal notranslate"><span class="pre">&#64;api.patch</span></code>, <code class="docutils literal notranslate"><span class="pre">&#64;api.delete</span></code>, and <code class="docutils literal notranslate"><span class="pre">&#64;api.websocket_route</span></code>, plus the same on
route groups. Registering <code class="docutils literal notranslate"><span class="pre">&#64;api.get(&quot;/x&quot;)</span></code> and <code class="docutils literal notranslate"><span class="pre">&#64;api.post(&quot;/x&quot;)</span></code> as separate
handlers on one path now works (same-path routes are allowed when their
methods are disjoint).</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">resp.delete_cookie(key,</span> <span class="pre">...)</span></code></strong> — expire a cookie on the client (mirrors
<code class="docutils literal notranslate"><span class="pre">set_cookie</span></code>’s <code class="docutils literal notranslate"><span class="pre">path</span></code>/<code class="docutils literal notranslate"><span class="pre">domain</span></code>/<code class="docutils literal notranslate"><span class="pre">secure</span></code>/<code class="docutils literal notranslate"><span class="pre">httponly</span></code>/<code class="docutils literal notranslate"><span class="pre">samesite</span></code>).</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">resp.vary(*fields)</span></code></strong> — add field names to the <code class="docutils literal notranslate"><span class="pre">Vary</span></code> header (merged and
de-duplicated). New <code class="docutils literal notranslate"><span class="pre">API(auto_vary=True)</span></code> emits <code class="docutils literal notranslate"><span class="pre">Vary:</span> <span class="pre">Accept</span></code> on
content-negotiated responses (correct for shared caches); off by default,
slated to default on in 6.0.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">responder.middleware.HSTSMiddleware</span></code></strong> — the HSTS header middleware, usable
directly via <code class="docutils literal notranslate"><span class="pre">add_middleware</span></code> to customize <code class="docutils literal notranslate"><span class="pre">max_age</span></code>/<code class="docutils literal notranslate"><span class="pre">preload</span></code>.</p></li>
</ul>
</section>
</section>
<section id="v5-0-0-2026-06-28">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v4.1.0..v5.0.0">v5.0.0</a> - 2026-06-28<a class="headerlink" href="#v5-0-0-2026-06-28" title="Link to this heading"></a></h2>
<p>A major release: fully type-driven request/response I/O, composable dependency
injection, plan-driven OpenAPI, secure-by-default sessions, and a deferred
middleware stack — layered onto the unchanged <code class="docutils literal notranslate"><span class="pre">(req,</span> <span class="pre">resp)</span></code> core. Breaking
changes are staged behind the <a class="reference external" href="https://github.com/kennethreitz/responder/blob/main/docs/migration-v5.md">v5 migration guide</a>.</p>
<section id="id79">
<h3>Added<a class="headerlink" href="#id79" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong>Type-hint-driven OpenAPI.</strong> The schema is now generated from each route’s
methods, body/response models, and <code class="docutils literal notranslate"><span class="pre">Query</span></code>/<code class="docutils literal notranslate"><span class="pre">Header</span></code>/<code class="docutils literal notranslate"><span class="pre">Cookie</span></code> markers — so
routes <strong>without</strong> a YAML docstring now appear in the spec (with parameters,
request/response schemas, and an automatic <code class="docutils literal notranslate"><span class="pre">422</span></code> for validating routes).
Docstring YAML is deep-merged on top as an override. New
<code class="docutils literal notranslate"><span class="pre">&#64;api.route(...,</span> <span class="pre">include_in_schema=False)</span></code> hides a route; internal routes
(schema/docs/static/metrics) are auto-excluded.</p></li>
<li><p><strong>Typed parameter markers.</strong> <code class="docutils literal notranslate"><span class="pre">Query()</span></code>, <code class="docutils literal notranslate"><span class="pre">Header()</span></code>, <code class="docutils literal notranslate"><span class="pre">Cookie()</span></code>, and <code class="docutils literal notranslate"><span class="pre">Path()</span></code>
(exported from <code class="docutils literal notranslate"><span class="pre">responder</span></code>) inject validated, type-coerced query parameters,
headers, cookies, and path parameters as handler arguments —
<code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">search(req,</span> <span class="pre">resp,</span> <span class="pre">*,</span> <span class="pre">q:</span> <span class="pre">str</span> <span class="pre">=</span> <span class="pre">Query(...),</span> <span class="pre">limit:</span> <span class="pre">int</span> <span class="pre">=</span> <span class="pre">Query(10))</span></code> —
with <code class="docutils literal notranslate"><span class="pre">422</span></code> on a missing required value or a validation failure. Supports
defaults, aliases, and sequence types (<code class="docutils literal notranslate"><span class="pre">list[int]</span></code> from repeated query keys).</p></li>
<li><p><strong>Return annotation as <code class="docutils literal notranslate"><span class="pre">response_model</span></code>.</strong> A Pydantic return annotation
(<code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">handler(req,</span> <span class="pre">resp)</span> <span class="pre">-&gt;</span> <span class="pre">ItemOut</span></code>) now validates/serializes the response
against that model (coerce types, strip undeclared fields), the same as an
explicit <code class="docutils literal notranslate"><span class="pre">response_model=</span></code>.</p></li>
<li><p><strong>Composable dependency injection.</strong> A dependency provider can now depend on
<em>other</em> providers by declaring them as parameters — resolved recursively,
memoized across the whole request graph, torn down in reverse-topological
order, with cycle detection. App-scoped dependencies may compose with other
app-scoped ones (but never with the request or request-scoped deps).
Providers receive the request only via a <code class="docutils literal notranslate"><span class="pre">req</span></code>/<code class="docutils literal notranslate"><span class="pre">request</span></code> parameter or a
<code class="docutils literal notranslate"><span class="pre">Request</span></code>/<code class="docutils literal notranslate"><span class="pre">WebSocket</span></code> annotation (a sole-unnamed-param shim warns for one
cycle). New <code class="docutils literal notranslate"><span class="pre">DependencyError</span></code>/<code class="docutils literal notranslate"><span class="pre">DependencyCycleError</span></code>/<code class="docutils literal notranslate"><span class="pre">DependencyScopeError</span></code>/
<code class="docutils literal notranslate"><span class="pre">DependencyResolutionError</span></code> exceptions; <code class="docutils literal notranslate"><span class="pre">req</span></code>/<code class="docutils literal notranslate"><span class="pre">request</span></code>/<code class="docutils literal notranslate"><span class="pre">resp</span></code>/<code class="docutils literal notranslate"><span class="pre">response</span></code>/
<code class="docutils literal notranslate"><span class="pre">ws</span></code>/<code class="docutils literal notranslate"><span class="pre">websocket</span></code> are reserved dependency names.</p></li>
<li><p><strong>Async-native backends.</strong> Session and rate-limit backends may now expose
async methods (<code class="docutils literal notranslate"><span class="pre">aget</span></code>/<code class="docutils literal notranslate"><span class="pre">aset</span></code>/<code class="docutils literal notranslate"><span class="pre">adelete</span></code>/<code class="docutils literal notranslate"><span class="pre">atouch</span></code>, <code class="docutils literal notranslate"><span class="pre">ahit</span></code>) that are awaited
directly instead of run in a thread — with <code class="docutils literal notranslate"><span class="pre">AsyncRedisSessionBackend</span></code> and
<code class="docutils literal notranslate"><span class="pre">AsyncRedisBackend</span></code> built in (<code class="docutils literal notranslate"><span class="pre">redis.asyncio</span></code>). <code class="docutils literal notranslate"><span class="pre">RateLimiter.acheck()</span></code> and
<code class="docutils literal notranslate"><span class="pre">.install()</span></code> work with any backend. Backend <code class="docutils literal notranslate"><span class="pre">Protocol</span></code>s are exported for
typing.</p></li>
<li><p><strong>Sliding server-side session TTL via <code class="docutils literal notranslate"><span class="pre">touch</span></code>.</strong> An unchanged read-only
request now refreshes the backend TTL with <code class="docutils literal notranslate"><span class="pre">touch</span></code>/<code class="docutils literal notranslate"><span class="pre">atouch</span></code> (no full
re-serialize) while a mutation still does a full <code class="docutils literal notranslate"><span class="pre">set</span></code> — fixing the
premature-logout/dirty-tracking trade-off correctly.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">api.add_exception_handler(exc_or_status,</span> <span class="pre">handler)</span></code></strong> registers an error
handler programmatically (the <code class="docutils literal notranslate"><span class="pre">&#64;api.exception_handler</span></code> decorator now delegates
to it). A handler for <code class="docutils literal notranslate"><span class="pre">500</span></code>/<code class="docutils literal notranslate"><span class="pre">Exception</span></code> installs the catch-all server-error
handler.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">api.add_middleware()</span></code> now works after construction</strong> — middleware is
collected and the stack is built lazily on first request.</p></li>
</ul>
</section>
<section id="id80">
<h3>Security<a class="headerlink" href="#id80" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong>Secure-by-default sessions.</strong> The session signing key no longer defaults to
the public <code class="docutils literal notranslate"><span class="pre">&quot;NOTASECRET&quot;</span></code>. With <code class="docutils literal notranslate"><span class="pre">sessions=&quot;auto&quot;</span></code> (the default) Responder uses
your <code class="docutils literal notranslate"><span class="pre">secret_key</span></code> / <code class="docutils literal notranslate"><span class="pre">RESPONDER_SECRET_KEY</span></code>, else mints a random per-process key
with a loud warning (set a key for stable, multi-worker sessions).
<code class="docutils literal notranslate"><span class="pre">secret_key=&quot;NOTASECRET&quot;</span></code> now raises. Session cookies are <code class="docutils literal notranslate"><span class="pre">Secure</span></code> by default
in production (<code class="docutils literal notranslate"><span class="pre">session_https_only=None</span></code>), and <code class="docutils literal notranslate"><span class="pre">SameSite=None</span></code> without Secure
is rejected.</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">sessions=</span></code> and <code class="docutils literal notranslate"><span class="pre">session_max_age=</span></code> knobs.</strong> <code class="docutils literal notranslate"><span class="pre">sessions=True</span></code> requires a real
key (raises otherwise); <code class="docutils literal notranslate"><span class="pre">sessions=False</span></code> disables session middleware entirely
and makes <code class="docutils literal notranslate"><span class="pre">req.session</span></code>/<code class="docutils literal notranslate"><span class="pre">resp.session</span></code> raise a guiding <code class="docutils literal notranslate"><span class="pre">RuntimeError</span></code>.</p></li>
</ul>
</section>
<section id="id81">
<h3>Changed<a class="headerlink" href="#id81" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">resp.session</span></code> is now a property that delegates to <code class="docutils literal notranslate"><span class="pre">req.session</span></code> (so
<code class="docutils literal notranslate"><span class="pre">resp.session</span> <span class="pre">=</span> <span class="pre">{...}</span></code> actually writes through to the cookie). Reading either
with sessions disabled raises <code class="docutils literal notranslate"><span class="pre">RuntimeError</span></code>.</p></li>
<li><p><strong>Deferred middleware stack.</strong> The ASGI stack is assembled lazily with
<code class="docutils literal notranslate"><span class="pre">ServerErrorMiddleware</span></code> as the outermost application layer (so it catches
errors from <em>any</em> middleware — sessions, CORS, user middleware) while the
logging/request-id tier wraps even it, so <code class="docutils literal notranslate"><span class="pre">X-Request-ID</span></code> and the real status
now appear on <code class="docutils literal notranslate"><span class="pre">500</span></code> responses. <code class="docutils literal notranslate"><span class="pre">API.app</span></code> is a lazy read-only property; mutate
the stack via <code class="docutils literal notranslate"><span class="pre">add_middleware()</span></code> or wrap the API object for a truly-outermost
layer. User middleware now sits inside <code class="docutils literal notranslate"><span class="pre">ServerErrorMiddleware</span></code> (its errors are
caught), and sessions sit below it (a write is not persisted on an unhandled
<code class="docutils literal notranslate"><span class="pre">500</span></code>).</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">req.method</span></code> is now UPPERCASE</strong> (<code class="docutils literal notranslate"><span class="pre">&quot;GET&quot;</span></code> not <code class="docutils literal notranslate"><span class="pre">&quot;get&quot;</span></code>), matching
Flask/FastAPI/Starlette/stdlib. For one deprecation cycle it returns an
<code class="docutils literal notranslate"><span class="pre">HTTPMethod</span></code> (a <code class="docutils literal notranslate"><span class="pre">str</span></code> subclass) that still compares case-insensitively — so
<code class="docutils literal notranslate"><span class="pre">req.method</span> <span class="pre">==</span> <span class="pre">&quot;get&quot;</span></code> keeps working but emits a <code class="docutils literal notranslate"><span class="pre">DeprecationWarning</span></code>. Hash-
based membership (<code class="docutils literal notranslate"><span class="pre">req.method</span> <span class="pre">in</span> <span class="pre">{&quot;get&quot;}</span></code>) is case-sensitive and misses; use
<code class="docutils literal notranslate"><span class="pre">==</span></code>, a tuple/list, or uppercase keys. Removed in Responder 6.0.</p></li>
</ul>
</section>
</section>
<section id="v4-1-0-2026-06-28">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v4.0.0..v4.1.0">v4.1.0</a> - 2026-06-28<a class="headerlink" href="#v4-1-0-2026-06-28" title="Link to this heading"></a></h2>
<p>A backward-compatible quality release: verified correctness and
resource-safety fixes, additive security hardening, and developer-experience
improvements. No existing call signatures change.</p>
<section id="id82">
<h3>Added<a class="headerlink" href="#id82" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong><code class="docutils literal notranslate"><span class="pre">responder.types</span></code></strong>: public <code class="docutils literal notranslate"><span class="pre">Handler</span></code>, <code class="docutils literal notranslate"><span class="pre">Hook</span></code>, and <code class="docutils literal notranslate"><span class="pre">Dependency</span></code> type
aliases for annotating your own handlers and hooks.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">req</span></code>/<code class="docutils literal notranslate"><span class="pre">resp</span></code> hot surface (<code class="docutils literal notranslate"><span class="pre">headers</span></code>, <code class="docutils literal notranslate"><span class="pre">params</span></code>, <code class="docutils literal notranslate"><span class="pre">method</span></code>, <code class="docutils literal notranslate"><span class="pre">cookies</span></code>,
<code class="docutils literal notranslate"><span class="pre">mimetype</span></code>, <code class="docutils literal notranslate"><span class="pre">is_json</span></code>, <code class="docutils literal notranslate"><span class="pre">is_secure</span></code>, …) and the dynamic <code class="docutils literal notranslate"><span class="pre">status_codes</span></code>
constants are now statically typed, so the shipped <code class="docutils literal notranslate"><span class="pre">py.typed</span></code> marker actually
helps downstream type checkers (and removes internal <code class="docutils literal notranslate"><span class="pre">type:</span> <span class="pre">ignore</span></code>s).</p></li>
<li><p><strong>Type-hint-driven body injection</strong>: a handler parameter annotated with a
Pydantic model now receives the validated request body —
<code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">def</span> <span class="pre">create(req,</span> <span class="pre">resp,</span> <span class="pre">*,</span> <span class="pre">item:</span> <span class="pre">ItemIn)</span></code> — returning <code class="docutils literal notranslate"><span class="pre">422</span></code> on invalid
input. Works for sync and async handlers and coexists with path parameters
and dependencies. (Previously such a signature raised a <code class="docutils literal notranslate"><span class="pre">500</span></code>.) Use an
explicit <code class="docutils literal notranslate"><span class="pre">response_model=</span></code> for response validation.</p></li>
<li><p><strong>First-class Pydantic models</strong>: <code class="docutils literal notranslate"><span class="pre">resp.media</span> <span class="pre">=</span> <span class="pre">model</span></code> and <code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre">Model()</span></code>
now serialize correctly (across JSON, YAML, and MessagePack), as do
dataclasses. The JSON encoder also handles <code class="docutils literal notranslate"><span class="pre">datetime</span></code>, <code class="docutils literal notranslate"><span class="pre">date</span></code>, <code class="docutils literal notranslate"><span class="pre">time</span></code>,
<code class="docutils literal notranslate"><span class="pre">UUID</span></code>, <code class="docutils literal notranslate"><span class="pre">Decimal</span></code>, <code class="docutils literal notranslate"><span class="pre">set</span></code>, and <code class="docutils literal notranslate"><span class="pre">bytes</span></code> natively — <code class="docutils literal notranslate"><span class="pre">resp.media</span> <span class="pre">=</span> <span class="pre">{&quot;created_at&quot;:</span> <span class="pre">datetime.now()}</span></code> no longer 500s.</p></li>
<li><p><strong>Pluggable type encoder</strong>: <code class="docutils literal notranslate"><span class="pre">API(encoder=...)</span></code> accepts an <code class="docutils literal notranslate"><span class="pre">obj</span> <span class="pre">-&gt;</span> <span class="pre">serializable</span></code> callable applied across <strong>all</strong> response formats (JSON, YAML,
MessagePack) to serialize custom types. It’s tried first and falls back to
the built-in conversions.</p></li>
<li><p><strong>Flask-style tuple returns</strong>: a handler may <code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre">body,</span> <span class="pre">status</span></code> or
<code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre">body,</span> <span class="pre">status,</span> <span class="pre">headers</span></code> (previously these were silently dropped).</p></li>
<li><p><strong><code class="docutils literal notranslate"><span class="pre">responder.abort(status_code,</span> <span class="pre">*,</span> <span class="pre">detail=None,</span> <span class="pre">headers=None)</span></code></strong> raises a
rendered HTTP error from anywhere in a handler or dependency, without
importing Starlette.</p></li>
<li><p><strong>Bare lifecycle decorators</strong>: <code class="docutils literal notranslate"><span class="pre">&#64;api.before_request</span></code> and <code class="docutils literal notranslate"><span class="pre">&#64;api.after_request</span></code>
now work without the parentheses, alongside the existing called forms.</p></li>
<li><p><strong>Sync body access</strong>: <code class="docutils literal notranslate"><span class="pre">req.media_sync()</span></code> and <code class="docutils literal notranslate"><span class="pre">req.text_sync</span></code> let synchronous
handlers read the request body (they bridge to the loop from the worker
thread Responder already runs sync handlers in).</p></li>
</ul>
</section>
<section id="id83">
<h3>Changed<a class="headerlink" href="#id83" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong><code class="docutils literal notranslate"><span class="pre">response_model</span></code> now fails closed instead of leaking.</strong> Previously a
response whose data didn’t satisfy its declared <code class="docutils literal notranslate"><span class="pre">response_model</span></code> was sent
through <em>unvalidated</em> (wrong types, undeclared fields and all). It now
coerces and strips as documented, and on a genuine validation failure raises
in debug mode or returns a <code class="docutils literal notranslate"><span class="pre">500</span></code> (never the unvalidated payload) in
production. Valid responses are unaffected; <code class="docutils literal notranslate"><span class="pre">datetime</span></code>/<code class="docutils literal notranslate"><span class="pre">UUID</span></code>/etc. fields now
serialize instead of 500-ing. List responses are validated item-by-item.</p></li>
<li><p>Malformed request bodies now return <strong>400</strong> instead of <strong>500</strong>: invalid
JSON, YAML, or MessagePack raise a rendered <code class="docutils literal notranslate"><span class="pre">400</span></code>, and binary parts in a
<code class="docutils literal notranslate"><span class="pre">req.media(&quot;form&quot;)</span></code> call are skipped rather than crashing.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">API(auto_escape=...)</span></code> is now actually forwarded to the template environment
(it was previously ignored).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">resp.ok</span></code> reads as <code class="docutils literal notranslate"><span class="pre">200</span></code>-based success until a status code is set, instead of
raising.</p></li>
<li><p>Per-request overhead trimmed: coroutine-function detection for views and
hooks is memoized, and <code class="docutils literal notranslate"><span class="pre">req.params</span></code> reads the raw query string from the ASGI
scope instead of rebuilding and re-parsing the full URL.</p></li>
</ul>
</section>
<section id="id84">
<h3>Fixed<a class="headerlink" href="#id84" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong>Mounted-app routing</strong>: a mount prefix now only matches on a path-segment
boundary, so e.g. <code class="docutils literal notranslate"><span class="pre">GET</span> <span class="pre">/subscribe</span></code> is no longer mis-routed into an app
mounted at <code class="docutils literal notranslate"><span class="pre">/sub</span></code> (and sub-paths keep their leading slash). More specific
(longer) mount prefixes resolve first.</p></li>
<li><p><strong>Dependency teardown leaks</strong>: a failing generator-dependency teardown no
longer skips the remaining teardowns — each runs best-effort and failures
are logged, so connections/files/locks are always released. Applies to HTTP
routes, WebSocket routes, and app-scoped shutdown.</p></li>
<li><p><strong>Event-loop blocking</strong>: server-side session backends (e.g. Redis) now run
their <code class="docutils literal notranslate"><span class="pre">get</span></code>/<code class="docutils literal notranslate"><span class="pre">set</span></code>/<code class="docutils literal notranslate"><span class="pre">delete</span></code> off the event loop, <code class="docutils literal notranslate"><span class="pre">resp.file()</span></code> reads file
bytes in a worker thread, and the static <code class="docutils literal notranslate"><span class="pre">index.html</span></code> fallback reads off the
loop too — so these no longer stall the server from <code class="docutils literal notranslate"><span class="pre">async</span></code> handlers.</p></li>
<li><p><strong>Request-size enforcement</strong>: <code class="docutils literal notranslate"><span class="pre">max_request_size</span></code> is now enforced while the
body streams in (chunked or lying <code class="docutils literal notranslate"><span class="pre">Content-Length</span></code>) instead of buffering the
whole body first; also fixes an empty-body re-read.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">BackgroundQueue.__call__</span></code> no longer wraps work in a pointless
create-task-then-await; its await-to-completion semantics are now documented
(use <code class="docutils literal notranslate"><span class="pre">.task</span></code>/<code class="docutils literal notranslate"><span class="pre">.run</span></code> for fire-and-forget).</p></li>
</ul>
</section>
<section id="id85">
<h3>Security<a class="headerlink" href="#id85" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong>Default secret key warning</strong>: Responder now logs a loud warning when cookie
sessions are signed with the built-in <code class="docutils literal notranslate"><span class="pre">&quot;NOTASECRET&quot;</span></code> default key (outside
debug mode) — forged session data is otherwise trivial. Set
<code class="docutils literal notranslate"><span class="pre">API(secret_key=...)</span></code>.</p></li>
<li><p><strong>Session fixation defense</strong>: server-side sessions mint a fresh id when a
presented cookie doesn’t resolve, and a new <code class="docutils literal notranslate"><span class="pre">regenerate_session(req)</span></code> helper
(<code class="docutils literal notranslate"><span class="pre">responder.ext.sessions</span></code>) rotates the id after login/privilege change.</p></li>
<li><p><strong>Session cookie controls</strong>: <code class="docutils literal notranslate"><span class="pre">API(session_cookie=...,</span> <span class="pre">session_https_only=...,</span> <span class="pre">session_same_site=...)</span></code> configure the session cookie for both cookie-payload
and server-side sessions.</p></li>
<li><p><strong>GraphQL hardening</strong>: <code class="docutils literal notranslate"><span class="pre">api.graphql(...,</span> <span class="pre">graphiql=...,</span> <span class="pre">introspection=...,</span> <span class="pre">max_depth=...)</span></code> can disable the in-browser IDE, reject schema-introspection
queries, and cap query nesting depth (a DoS guard) for production.</p></li>
<li><p><strong>Path-traversal jail</strong>: <code class="docutils literal notranslate"><span class="pre">resp.file(path,</span> <span class="pre">root=...)</span></code>, <code class="docutils literal notranslate"><span class="pre">resp.stream_file(...,</span> <span class="pre">root=...)</span></code>, and <code class="docutils literal notranslate"><span class="pre">resp.download(...,</span> <span class="pre">root=...)</span></code> resolve <code class="docutils literal notranslate"><span class="pre">path</span></code> under <code class="docutils literal notranslate"><span class="pre">root</span></code> and
return <code class="docutils literal notranslate"><span class="pre">404</span></code> on any <code class="docutils literal notranslate"><span class="pre">..</span></code>/symlink escape — use whenever the path is user input.</p></li>
<li><p><strong>Open-redirect guard</strong>: <code class="docutils literal notranslate"><span class="pre">resp.redirect(location,</span> <span class="pre">allow_external=False)</span></code> (and
<code class="docutils literal notranslate"><span class="pre">api.redirect(...)</span></code>) refuse to redirect to an absolute or protocol-relative
URL — use for user-supplied locations.</p></li>
</ul>
</section>
</section>
<section id="v4-0-0-2026-06-12">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v3.12.0..v4.0.0">v4.0.0</a> - 2026-06-12<a class="headerlink" href="#v4-0-0-2026-06-12" title="Link to this heading"></a></h2>
<section id="id86">
<h3>Changed<a class="headerlink" href="#id86" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><strong>Breaking:</strong> Slimmed the default install from ~60 packages to ~30 by
moving heavy dependencies behind extras:</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">pueblo[sfa-full]</span></code> (which pulls in <code class="docutils literal notranslate"><span class="pre">s3fs</span></code>, <code class="docutils literal notranslate"><span class="pre">aiobotocore</span></code>, <code class="docutils literal notranslate"><span class="pre">aiohttp</span></code>,
<code class="docutils literal notranslate"><span class="pre">libarchive-c</span></code>, and friends) is now the <code class="docutils literal notranslate"><span class="pre">cli</span></code> extra. <code class="docutils literal notranslate"><span class="pre">responder</span> <span class="pre">run</span></code>
still works out of the box for local modules and file paths
(<code class="docutils literal notranslate"><span class="pre">app:api</span></code>, <code class="docutils literal notranslate"><span class="pre">myapp/core.py</span></code>); only remote targets (URLs, <code class="docutils literal notranslate"><span class="pre">github://</span></code>,
cloud storage) need <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">'responder[cli]'</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">graphene</span></code> and <code class="docutils literal notranslate"><span class="pre">graphql-core</span></code> are now the <code class="docutils literal notranslate"><span class="pre">graphql</span></code> extra. Install
with <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">'responder[graphql]'</span></code> to use <code class="docutils literal notranslate"><span class="pre">api.graphql()</span></code></p></li>
</ul>
</li>
</ul>
</section>
</section>
<section id="v3-12-0-2026-06-12">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v3.11.0..v3.12.0">v3.12.0</a> - 2026-06-12<a class="headerlink" href="#v3-12-0-2026-06-12" title="Link to this heading"></a></h2>
<section id="id87">
<h3>Added<a class="headerlink" href="#id87" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Built-in metrics: <code class="docutils literal notranslate"><span class="pre">API(metrics_route=&quot;/metrics&quot;)</span></code> serves request counts
and latency histograms in Prometheus text format, zero dependencies.
Labels use route patterns (<code class="docutils literal notranslate"><span class="pre">/users/{id}</span></code>) so cardinality stays bounded;
error responses are recorded with their real status codes</p></li>
<li><p>Server-side sessions: <code class="docutils literal notranslate"><span class="pre">API(session_backend=...)</span></code> stores session data in
a backend (<code class="docutils literal notranslate"><span class="pre">MemorySessionBackend</span></code>, <code class="docutils literal notranslate"><span class="pre">RedisSessionBackend</span></code>, or any object
with <code class="docutils literal notranslate"><span class="pre">get</span></code>/<code class="docutils literal notranslate"><span class="pre">set</span></code>/<code class="docutils literal notranslate"><span class="pre">delete</span></code>) with only an opaque ID in the cookie —
enabling revocation and unbounded session size. Handler code is unchanged</p></li>
<li><p>Query-parameter validation: <code class="docutils literal notranslate"><span class="pre">&#64;api.route(...,</span> <span class="pre">params_model=Model)</span></code>
coerces and validates query strings with Pydantic (<code class="docutils literal notranslate"><span class="pre">422</span></code> on failure),
exposes the instance as <code class="docutils literal notranslate"><span class="pre">req.state.validated_params</span></code>, maps repeated keys
to <code class="docutils literal notranslate"><span class="pre">list</span></code> fields, and documents the parameters in the OpenAPI spec</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">resp.render(template,</span> <span class="pre">**context)</span></code> — render a Jinja2 template as the
HTML response body in one call</p></li>
</ul>
</section>
</section>
<section id="v3-11-0-2026-06-11">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v3.10.0..v3.11.0">v3.11.0</a> - 2026-06-11<a class="headerlink" href="#v3-11-0-2026-06-11" title="Link to this heading"></a></h2>
<section id="id88">
<h3>Added<a class="headerlink" href="#id88" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>HTTP range requests: <code class="docutils literal notranslate"><span class="pre">resp.file()</span></code> and <code class="docutils literal notranslate"><span class="pre">resp.stream_file()</span></code> answer
<code class="docutils literal notranslate"><span class="pre">Range:</span> <span class="pre">bytes=...</span></code> with <code class="docutils literal notranslate"><span class="pre">206</span> <span class="pre">Partial</span> <span class="pre">Content</span></code> (suffix and open-ended
ranges, <code class="docutils literal notranslate"><span class="pre">416</span></code> for unsatisfiable, <code class="docutils literal notranslate"><span class="pre">Accept-Ranges</span></code> advertised) — enables
video seeking and resumable downloads</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">resp.download(path,</span> <span class="pre">filename=...)</span></code> serves files as attachments with
proper <code class="docutils literal notranslate"><span class="pre">Content-Disposition</span></code> (RFC 5987 encoding for non-ASCII names),
streamed and resumable</p></li>
<li><p>Request timeouts: <code class="docutils literal notranslate"><span class="pre">API(request_timeout=seconds)</span></code> answers overrunning
handlers with <code class="docutils literal notranslate"><span class="pre">504</span> <span class="pre">Gateway</span> <span class="pre">Timeout</span></code> (content-negotiated); dependency
teardowns still run</p></li>
</ul>
</section>
<section id="performance">
<h3>Performance<a class="headerlink" href="#performance" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Route resolution is cached per (method, path) with invalidation on
registration — ~10% faster dispatch at 81 routes, growing with route
count</p></li>
</ul>
</section>
</section>
<section id="v3-10-0-2026-06-11">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v3.9.1..v3.10.0">v3.10.0</a> - 2026-06-11<a class="headerlink" href="#v3-10-0-2026-06-11" title="Link to this heading"></a></h2>
<section id="id89">
<h3>Added<a class="headerlink" href="#id89" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Trailing-slash redirects: requests that miss only by a trailing slash get
a <code class="docutils literal notranslate"><span class="pre">307</span></code> to the canonical path, preserving method and query string.
Disable with <code class="docutils literal notranslate"><span class="pre">API(redirect_slashes=False)</span></code></p></li>
<li><p>Request size limits: <code class="docutils literal notranslate"><span class="pre">API(max_request_size=bytes)</span></code> returns <code class="docutils literal notranslate"><span class="pre">413</span></code> for
oversized bodies — fast-fails on <code class="docutils literal notranslate"><span class="pre">Content-Length</span></code> and enforces
cumulatively for chunked/streamed uploads</p></li>
<li><p>Automatic ETags: <code class="docutils literal notranslate"><span class="pre">API(auto_etag=True)</span></code> adds a content-hash <code class="docutils literal notranslate"><span class="pre">ETag</span></code> to GET
responses with full <code class="docutils literal notranslate"><span class="pre">304</span> <span class="pre">Not</span> <span class="pre">Modified</span></code> handling; an explicit <code class="docutils literal notranslate"><span class="pre">resp.etag</span></code>
always wins</p></li>
<li><p>After-response background tasks: <code class="docutils literal notranslate"><span class="pre">resp.background(func,</span> <span class="pre">*args)</span></code> defers
work until the client has the response (sync and async, ordered)</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">resp.cache_control(...)</span></code> helper for building <code class="docutils literal notranslate"><span class="pre">Cache-Control</span></code> headers</p></li>
</ul>
</section>
<section id="id90">
<h3>Fixed<a class="headerlink" href="#id90" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>A <code class="docutils literal notranslate"><span class="pre">413</span></code> raised while reading the body during <code class="docutils literal notranslate"><span class="pre">request_model</span></code> validation
is no longer swallowed into a <code class="docutils literal notranslate"><span class="pre">422</span></code></p></li>
</ul>
</section>
<section id="id91">
<h3>Changed<a class="headerlink" href="#id91" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Trailing-slash redirects are on by default (previously such requests
were 404s)</p></li>
</ul>
</section>
</section>
<section id="v3-9-1-2026-06-11">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v3.9.0..v3.9.1">v3.9.1</a> - 2026-06-11<a class="headerlink" href="#v3-9-1-2026-06-11" title="Link to this heading"></a></h2>
<section id="id92">
<h3>Added<a class="headerlink" href="#id92" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Conditional request support: set <code class="docutils literal notranslate"><span class="pre">resp.etag</span></code> or <code class="docutils literal notranslate"><span class="pre">resp.last_modified</span></code> and
matching <code class="docutils literal notranslate"><span class="pre">If-None-Match</span></code>/<code class="docutils literal notranslate"><span class="pre">If-Modified-Since</span></code> requests automatically get
<code class="docutils literal notranslate"><span class="pre">304</span> <span class="pre">Not</span> <span class="pre">Modified</span></code> (RFC 7232 semantics: <code class="docutils literal notranslate"><span class="pre">If-None-Match</span></code> precedence, weak
comparison, GET/HEAD only)</p></li>
<li><p>Request body streaming: <code class="docutils literal notranslate"><span class="pre">async</span> <span class="pre">for</span> <span class="pre">chunk</span> <span class="pre">in</span> <span class="pre">req.stream()</span></code> iterates large
uploads without buffering</p></li>
<li><p>Pluggable rate-limiter backends: <code class="docutils literal notranslate"><span class="pre">RateLimiter(backend=...)</span></code> with the
in-memory default plus a new <code class="docutils literal notranslate"><span class="pre">RedisBackend</span></code> for multi-process deployments</p></li>
<li><p>Application state: <code class="docutils literal notranslate"><span class="pre">api.state</span></code> namespace, reachable from handlers via
<code class="docutils literal notranslate"><span class="pre">req.api.state</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">req.api</span></code> is now populated with the owning <code class="docutils literal notranslate"><span class="pre">API</span></code> instance (it was always
<code class="docutils literal notranslate"><span class="pre">None</span></code> before)</p></li>
</ul>
</section>
<section id="id93">
<h3>Fixed<a class="headerlink" href="#id93" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">API(static_dir=None)</span></code> crashed on every route registration — the static
fallback assertion now only applies when no endpoint is given</p></li>
<li><p>The static-fallback error is a <code class="docutils literal notranslate"><span class="pre">ValueError</span></code> instead of a bare <code class="docutils literal notranslate"><span class="pre">assert</span></code></p></li>
</ul>
</section>
<section id="id94">
<h3>Performance<a class="headerlink" href="#id94" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Request headers are parsed into the case-insensitive dict lazily, on
first access (~5% faster dispatch on header-heavy requests that don’t
read headers)</p></li>
</ul>
</section>
</section>
<section id="v3-9-0-2026-06-11">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v3.8.0..v3.9.0">v3.9.0</a> - 2026-06-11<a class="headerlink" href="#v3-9-0-2026-06-11" title="Link to this heading"></a></h2>
<section id="id95">
<h3>Added<a class="headerlink" href="#id95" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Dependency injection for WebSocket handlers: declare path parameters and
registered dependencies by name after the <code class="docutils literal notranslate"><span class="pre">ws</span></code> argument. Request-scoped
providers taking a parameter receive the WebSocket; generator teardown
runs when the handler finishes. Handlers that only take <code class="docutils literal notranslate"><span class="pre">ws</span></code> are unaffected</p></li>
<li><p>OpenAPI 3.1 support (<code class="docutils literal notranslate"><span class="pre">openapi=&quot;3.1.0&quot;</span></code>)</p></li>
<li><p>The OpenAPI schema endpoint now serves JSON when requested via
<code class="docutils literal notranslate"><span class="pre">Accept:</span> <span class="pre">application/json</span></code>, or always when <code class="docutils literal notranslate"><span class="pre">openapi_route</span></code> ends in <code class="docutils literal notranslate"><span class="pre">.json</span></code></p></li>
<li><p>Path parameters are documented automatically in the OpenAPI spec from
route patterns (<code class="docutils literal notranslate"><span class="pre">{id:int}</span></code> → required integer parameter)</p></li>
<li><p>Built-in error responses (404, 405) are content-negotiated: JSON clients
receive <code class="docutils literal notranslate"><span class="pre">{&quot;error&quot;:</span> <span class="pre">...}</span></code> bodies instead of plain text</p></li>
</ul>
</section>
<section id="id96">
<h3>Fixed<a class="headerlink" href="#id96" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>OpenAPI paths no longer leak convertor patterns (<code class="docutils literal notranslate"><span class="pre">/users/{id:int}</span></code> is now
emitted as the spec-compliant <code class="docutils literal notranslate"><span class="pre">/users/{id}</span></code>)</p></li>
<li><p>Registering a duplicate route now raises <code class="docutils literal notranslate"><span class="pre">ValueError</span></code> (previously an
<code class="docutils literal notranslate"><span class="pre">assert</span></code> that disappears under <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-O</span></code>)</p></li>
<li><p>Removed dead <code class="docutils literal notranslate"><span class="pre">_exception_handlers</span></code> bookkeeping in <code class="docutils literal notranslate"><span class="pre">API.exception_handler</span></code></p></li>
</ul>
</section>
<section id="id97">
<h3>Changed<a class="headerlink" href="#id97" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">mypy</span></code> now passes with zero errors across the codebase (was 25); <code class="docutils literal notranslate"><span class="pre">ruff</span></code>
is clean as well</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">types-pyyaml</span></code> added to the <code class="docutils literal notranslate"><span class="pre">test</span></code> extra</p></li>
</ul>
</section>
</section>
<section id="v3-8-0-2026-06-11">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v3.7.0..v3.8.0">v3.8.0</a> - 2026-06-11<a class="headerlink" href="#v3-8-0-2026-06-11" title="Link to this heading"></a></h2>
<section id="id98">
<h3>Added<a class="headerlink" href="#id98" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Handlers can return values: a <code class="docutils literal notranslate"><span class="pre">dict</span></code>/<code class="docutils literal notranslate"><span class="pre">list</span></code> sets <code class="docutils literal notranslate"><span class="pre">resp.media</span></code>, a <code class="docutils literal notranslate"><span class="pre">str</span></code> sets
<code class="docutils literal notranslate"><span class="pre">resp.text</span></code>, and <code class="docutils literal notranslate"><span class="pre">bytes</span></code> set <code class="docutils literal notranslate"><span class="pre">resp.content</span></code>. Returning <code class="docutils literal notranslate"><span class="pre">None</span></code> keeps the
mutate-<code class="docutils literal notranslate"><span class="pre">resp</span></code> behavior, so existing handlers are unaffected</p></li>
<li><p>App-scoped dependencies: <code class="docutils literal notranslate"><span class="pre">&#64;api.dependency(scope=&quot;app&quot;)</span></code> resolves the
provider once on first use and caches it for the application’s lifetime;
generator teardown runs at shutdown</p></li>
<li><p>Automatic <code class="docutils literal notranslate"><span class="pre">OPTIONS</span></code> responses with an <code class="docutils literal notranslate"><span class="pre">Allow</span></code> header for method-restricted routes</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">HEAD</span></code> requests are accepted wherever <code class="docutils literal notranslate"><span class="pre">GET</span></code> is</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">set_cookie()</span></code> gains a <code class="docutils literal notranslate"><span class="pre">samesite</span></code> parameter, defaulting to <code class="docutils literal notranslate"><span class="pre">&quot;lax&quot;</span></code></p></li>
<li><p>The validated <code class="docutils literal notranslate"><span class="pre">request_model</span></code> instance is now available to handlers as
<code class="docutils literal notranslate"><span class="pre">req.state.validated</span></code> — no need to re-parse the body</p></li>
</ul>
</section>
<section id="id99">
<h3>Changed<a class="headerlink" href="#id99" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Requests to an existing path with an unsupported method now return
<code class="docutils literal notranslate"><span class="pre">405</span> <span class="pre">Method</span> <span class="pre">Not</span> <span class="pre">Allowed</span></code> with an <code class="docutils literal notranslate"><span class="pre">Allow</span></code> header (previously 404)</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">RouteGroup.before_request</span></code> hooks are now scoped to the group’s prefix
(previously they silently applied to every route)</p></li>
</ul>
</section>
<section id="id100">
<h3>Performance<a class="headerlink" href="#id100" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>View signature inspection for dependency injection is cached per function</p></li>
</ul>
</section>
</section>
<section id="v3-7-0-2026-06-11">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v3.6.2..v3.7.0">v3.7.0</a> - 2026-06-11<a class="headerlink" href="#v3-7-0-2026-06-11" title="Link to this heading"></a></h2>
<section id="id101">
<h3>Added<a class="headerlink" href="#id101" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Dependency injection for route handlers: register providers with
<code class="docutils literal notranslate"><span class="pre">&#64;api.dependency()</span></code> (or <code class="docutils literal notranslate"><span class="pre">api.add_dependency(name,</span> <span class="pre">provider)</span></code>) and declare
them as view parameters by name. Supports sync/async functions and
generators (code after <code class="docutils literal notranslate"><span class="pre">yield</span></code> runs as teardown once the response is sent).
Providers accepting a parameter receive the current <code class="docutils literal notranslate"><span class="pre">Request</span></code>. Dependencies
resolve at most once per request; path parameters take precedence.</p></li>
<li><p>Per-route rate limiting via <code class="docutils literal notranslate"><span class="pre">RateLimiter.limit</span></code> decorator</p></li>
<li><p>WebSocket before-request hooks can now reject connections: closing the
socket in a hook short-circuits the route handler</p></li>
<li><p>WebSocket before-request hooks may now be sync functions (run in the threadpool)</p></li>
<li><p>Custom formats registered on <code class="docutils literal notranslate"><span class="pre">api.formats</span></code> now actually reach request
parsing and response negotiation (previously each request got a fresh
default format registry)</p></li>
</ul>
</section>
<section id="id102">
<h3>Fixed<a class="headerlink" href="#id102" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">{value:float}</span></code> path convertor matched garbage like <code class="docutils literal notranslate"><span class="pre">1a5</span></code> (unescaped regex
dot) and crashed with a 500 — now correctly returns 404</p></li>
<li><p>Literal characters in route paths are now regex-escaped, so <code class="docutils literal notranslate"><span class="pre">/file.json</span></code>
no longer matches <code class="docutils literal notranslate"><span class="pre">/fileXjson</span></code></p></li>
<li><p>Unbounded memory growth in <code class="docutils literal notranslate"><span class="pre">BackgroundQueue</span></code> — completed futures are now
pruned from <code class="docutils literal notranslate"><span class="pre">results</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">req.media(&quot;form&quot;)</span></code> crashed with a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> when the request had no
<code class="docutils literal notranslate"><span class="pre">Content-Type</span></code> header</p></li>
<li><p>Content negotiation returned an empty body for <code class="docutils literal notranslate"><span class="pre">Accept</span></code> headers matching
encode-incapable formats (e.g. <code class="docutils literal notranslate"><span class="pre">multipart/form-data</span></code>) — now falls through
to JSON</p></li>
</ul>
</section>
<section id="id103">
<h3>Changed<a class="headerlink" href="#id103" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">Request.url</span></code> and <code class="docutils literal notranslate"><span class="pre">Request.params</span></code> are now computed once and cached</p></li>
<li><p>Format registries are no longer rebuilt twice per request</p></li>
</ul>
</section>
</section>
<section id="v3-6-2-2026-04-12">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v3.6.1..v3.6.2">v3.6.2</a> - 2026-04-12<a class="headerlink" href="#v3-6-2-2026-04-12" title="Link to this heading"></a></h2>
<section id="id104">
<h3>Fixed<a class="headerlink" href="#id104" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>GraphQL error responses now correctly return 400 status instead of always 200</p></li>
<li><p>OpenAPI docs UI now respects custom <code class="docutils literal notranslate"><span class="pre">openapi_route</span></code> instead of hardcoding <code class="docutils literal notranslate"><span class="pre">/schema.yml</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">before_requests</span></code> default type mismatch that could crash routes called outside the router</p></li>
<li><p>Blocking synchronous file I/O in <code class="docutils literal notranslate"><span class="pre">Response.stream_file()</span></code> — now uses async I/O via anyio</p></li>
<li><p>Memory leak in rate limiter (empty bucket keys never cleaned up)</p></li>
<li><p>Race condition in rate limiter <code class="docutils literal notranslate"><span class="pre">check()</span></code> — added thread-safe locking</p></li>
<li><p>WSGI fallback catching all <code class="docutils literal notranslate"><span class="pre">TypeError</span></code>s instead of just call-signature mismatches</p></li>
<li><p>Pydantic request/response model validation crashing on non-dict bodies</p></li>
<li><p>Test assertions that could never fail (<code class="docutils literal notranslate"><span class="pre">or</span> <span class="pre">True</span></code>, <code class="docutils literal notranslate"><span class="pre">&lt;</span> <span class="pre">500</span></code> patterns)</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">CaseInsensitiveDict</span></code> missing <code class="docutils literal notranslate"><span class="pre">__delitem__</span></code>, <code class="docutils literal notranslate"><span class="pre">pop</span></code>, and <code class="docutils literal notranslate"><span class="pre">setdefault</span></code> overrides</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">assert</span></code> used for input validation in OpenAPI extension (stripped by <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-O</span></code>)</p></li>
<li><p>Potential XSS in GraphiQL template endpoint injection</p></li>
<li><p>Dead <code class="docutils literal notranslate"><span class="pre">or</span> <span class="pre">&quot;&quot;</span></code> in media format detection logic</p></li>
</ul>
</section>
<section id="id105">
<h3>Changed<a class="headerlink" href="#id105" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">DELETE</span></code> requests now participate in Pydantic request body validation</p></li>
<li><p>Simplified status code category check to use chained comparison</p></li>
</ul>
</section>
<section id="id106">
<h3>Removed<a class="headerlink" href="#id106" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Unused <code class="docutils literal notranslate"><span class="pre">method</span></code> parameter from <code class="docutils literal notranslate"><span class="pre">load_target()</span></code></p></li>
<li><p>Unused Node.js setup step from CI test workflow</p></li>
</ul>
</section>
</section>
<section id="v3-6-1-2026-04-12">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v3.6.0..v3.6.1">v3.6.1</a> - 2026-04-12<a class="headerlink" href="#v3-6-1-2026-04-12" title="Link to this heading"></a></h2>
<section id="id107">
<h3>Added<a class="headerlink" href="#id107" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Configurable GZip compression via <code class="docutils literal notranslate"><span class="pre">gzip</span></code> parameter on <code class="docutils literal notranslate"><span class="pre">API()</span></code> (defaults to <code class="docutils literal notranslate"><span class="pre">True</span></code>)</p></li>
</ul>
</section>
</section>
<section id="v3-6-0-2026-03-24">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v3.5.0..v3.6.0">v3.6.0</a> - 2026-03-24<a class="headerlink" href="#v3-6-0-2026-03-24" title="Link to this heading"></a></h2>
<section id="id108">
<h3>Added<a class="headerlink" href="#id108" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Built-in structured logging with per-request context (<code class="docutils literal notranslate"><span class="pre">enable_logging=True</span></code>)</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">api.log</span></code> — always-available logger, enriched with request context when logging is enabled</p></li>
<li><p>Automatic access logging with timing: <code class="docutils literal notranslate"><span class="pre">GET</span> <span class="pre">/path</span> <span class="pre">→</span> <span class="pre">200</span> <span class="pre">(1.2ms)</span></code></p></li>
<li><p>Request ID generation/forwarding via <code class="docutils literal notranslate"><span class="pre">X-Request-ID</span></code> header</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">contextvars</span></code>-based request context (ID, method, path, client IP) on every log record</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">responder.ext.logging</span></code> module: <code class="docutils literal notranslate"><span class="pre">get_logger()</span></code>, <code class="docutils literal notranslate"><span class="pre">RequestContext</span></code>, <code class="docutils literal notranslate"><span class="pre">RequestContextFilter</span></code></p></li>
</ul>
</li>
<li><p>CLAUDE.md project guide and <code class="docutils literal notranslate"><span class="pre">/release</span></code> command</p></li>
<li><p>Version number in docs sidebar</p></li>
</ul>
</section>
<section id="id109">
<h3>Changed<a class="headerlink" href="#id109" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Comprehensive documentation improvements across all pages</p>
<ul>
<li><p>Deployment: health checks, Docker Compose, Caddy, Procfile, production checklist</p></li>
<li><p>API reference: usage examples for every class</p></li>
<li><p>Feature tour: Pydantic validation, content negotiation, structured logging sections</p></li>
<li><p>Tutorials: modernized SQLAlchemy to <code class="docutils literal notranslate"><span class="pre">mapped_column()</span></code>, fixed deprecated <code class="docutils literal notranslate"><span class="pre">datetime.utcnow()</span></code>,
WebSocket <code class="docutils literal notranslate"><span class="pre">WebSocketDisconnect</span></code> handling, role-based auth, auth strategy guide</p></li>
<li><p>Testing: rate limiting and WSGI mount examples</p></li>
<li><p>Middleware: pure ASGI middleware example</p></li>
<li><p>Quickstart: links to all tutorials</p></li>
<li><p>Sandbox: full rewrite with project layout</p></li>
</ul>
</li>
<li><p>Docker example uses <code class="docutils literal notranslate"><span class="pre">uv</span></code> instead of pip</p></li>
<li><p>Backlog updated: removed implemented features, replaced HTTP/2 server push with dependency injection</p></li>
</ul>
</section>
<section id="id110">
<h3>Removed<a class="headerlink" href="#id110" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">uv.lock</span></code> — this is a library, not an application</p></li>
</ul>
</section>
</section>
<section id="v3-5-0-2026-03-24">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v3.4.0..v3.5.0">v3.5.0</a> - 2026-03-24<a class="headerlink" href="#v3-5-0-2026-03-24" title="Link to this heading"></a></h2>
<section id="id111">
<h3>Added<a class="headerlink" href="#id111" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>CI validation for Python 3.14, 3.14 free-threaded, and PyPy 3.11</p></li>
<li><p>Marimo notebook mounting docs and example</p></li>
<li><p>Type annotations for <code class="docutils literal notranslate"><span class="pre">routes.py</span></code></p></li>
</ul>
</section>
<section id="id112">
<h3>Changed<a class="headerlink" href="#id112" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Replaced deprecated <code class="docutils literal notranslate"><span class="pre">asyncio.iscoroutinefunction</span></code> with <code class="docutils literal notranslate"><span class="pre">inspect.iscoroutinefunction</span></code> ahead of Python 3.16 removal</p></li>
<li><p>Narrowed broad <code class="docutils literal notranslate"><span class="pre">except</span> <span class="pre">Exception</span></code> to specific exceptions in response model serialization and websocket chat example</p></li>
<li><p>Improved GraphQL API interface with expanded test coverage</p></li>
<li><p>Code formatting cleanup via pyproject-fmt and ruff</p></li>
<li><p>Dropped Python 3.9 from CI</p></li>
</ul>
</section>
<section id="id113">
<h3>Fixed<a class="headerlink" href="#id113" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>WSGI mount returning 400 when requesting the exact mount root path</p></li>
<li><p>Werkzeug 3.1.7 compatibility for trusted host validation in tests</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">future.result</span></code> bare property access in background task test (now properly calls <code class="docutils literal notranslate"><span class="pre">future.result()</span></code>)</p></li>
<li><p>OpenAPI template packaging and static file serving</p></li>
<li><p>RST title underline warning breaking docs CI</p></li>
</ul>
</section>
<section id="id114">
<h3>Removed<a class="headerlink" href="#id114" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Read the Docs configuration (docs hosted on GitHub Pages)</p></li>
</ul>
</section>
</section>
<section id="v3-4-0-2026-03-22">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v3.3.0..v3.4.0">v3.4.0</a> - 2026-03-22<a class="headerlink" href="#v3-4-0-2026-03-22" title="Link to this heading"></a></h2>
<section id="id115">
<h3>Changed<a class="headerlink" href="#id115" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Upgraded to Starlette 1.0</p></li>
<li><p>Added comprehensive docstrings across the codebase</p></li>
<li><p>Expanded API reference documentation</p></li>
</ul>
</section>
</section>
<section id="v3-3-0-2026-03-22">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v3.2.0..v3.3.0">v3.3.0</a> - 2026-03-22<a class="headerlink" href="#v3-3-0-2026-03-22" title="Link to this heading"></a></h2>
<section id="id116">
<h3>Added<a class="headerlink" href="#id116" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Full documentation rewrite: tutorials for REST APIs, SQLAlchemy, Flask migration</p></li>
<li><p>Auth, WebSocket, middleware, and configuration guides</p></li>
<li><p>Testing docs with prose, examples, and tips</p></li>
<li><p>GitHub Pages deployment for docs</p></li>
</ul>
</section>
<section id="id117">
<h3>Changed<a class="headerlink" href="#id117" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Reworked homepage prose</p></li>
<li><p>Rewrote CLI and API reference docs</p></li>
</ul>
</section>
</section>
<section id="v3-2-0-2026-03-22">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v3.0.0..v3.2.0">v3.2.0</a> - 2026-03-22<a class="headerlink" href="#v3-2-0-2026-03-22" title="Link to this heading"></a></h2>
<section id="id118">
<h3>Added<a class="headerlink" href="#id118" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Pydantic auto-validation: <code class="docutils literal notranslate"><span class="pre">request_model</span></code> validates input, returns 422 on failure</p></li>
<li><p>Pydantic auto-serialization: <code class="docutils literal notranslate"><span class="pre">response_model</span></code> strips extra fields from responses</p></li>
<li><p>Server-Sent Events: <code class="docutils literal notranslate"><span class="pre">&#64;resp.sse</span></code> for real-time streaming</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">resp.stream_file()</span></code> for streaming large files without loading into memory</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">&#64;api.after_request()</span></code> hooks</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">api.group(&quot;/prefix&quot;)</span></code> for route groups and API versioning</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">api.graphql(&quot;/path&quot;,</span> <span class="pre">schema=schema)</span></code> one-liner GraphQL setup</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">api</span> <span class="pre">=</span> <span class="pre">responder.API(request_id=True)</span></code> for automatic request ID generation</p></li>
<li><p>Built-in rate limiter: <code class="docutils literal notranslate"><span class="pre">RateLimiter(requests=100,</span> <span class="pre">period=60).install(api)</span></code></p></li>
<li><p>MessagePack format support: <code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">req.media(&quot;msgpack&quot;)</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">req.is_json</span></code>, <code class="docutils literal notranslate"><span class="pre">req.path_params</span></code>, <code class="docutils literal notranslate"><span class="pre">req.client</span></code> properties</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">api.exception_handler()</span></code> decorator for custom error handling</p></li>
<li><p>Lifespan context manager support</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">uuid</span></code> and <code class="docutils literal notranslate"><span class="pre">path</span></code> route convertors</p></li>
<li><p>PEP 561 <code class="docutils literal notranslate"><span class="pre">py.typed</span></code> marker</p></li>
<li><p>Pydantic support for OpenAPI schema generation</p></li>
</ul>
</section>
<section id="id119">
<h3>Changed<a class="headerlink" href="#id119" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Dependencies flattened: <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span> <span class="pre">responder</span></code> gets everything</p></li>
<li><p>Core deps reduced to starlette + uvicorn</p></li>
<li><p>TestClient lazy-loaded (no httpx import in production)</p></li>
<li><p>Before-request hooks can short-circuit by setting status code</p></li>
<li><p>Removed poethepoet task runner</p></li>
</ul>
</section>
<section id="id120">
<h3>Fixed<a class="headerlink" href="#id120" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Multipart parser losing headers when parts have multiple headers</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">url_for()</span></code> with typed route params (<code class="docutils literal notranslate"><span class="pre">{id:int}</span></code>)</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">resp.body</span></code> encoding crash on bytes content</p></li>
<li><p>GraphQL text query missing <code class="docutils literal notranslate"><span class="pre">await</span></code></p></li>
<li><p>Streaming responses not sending Content-Type headers</p></li>
<li><p>Python 3.9 compatibility for union type syntax</p></li>
</ul>
</section>
</section>
<section id="v3-0-0-2026-03-22">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v2.0.5..v3.0.0">v3.0.0</a> - 2026-03-22<a class="headerlink" href="#v3-0-0-2026-03-22" title="Link to this heading"></a></h2>
<section id="id121">
<h3>Added<a class="headerlink" href="#id121" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Platform: Added support for Python 3.10 - Python 3.13</p></li>
<li><p>CLI: <code class="docutils literal notranslate"><span class="pre">responder</span> <span class="pre">run</span></code> now also accepts a filesystem path on its <code class="docutils literal notranslate"><span class="pre">&lt;target&gt;</span></code>
argument, enabling usage on single-file applications.</p></li>
<li><p>CLI: <code class="docutils literal notranslate"><span class="pre">responder</span> <span class="pre">run</span></code> now also accepts URLs.</p></li>
</ul>
</section>
<section id="id122">
<h3>Changed<a class="headerlink" href="#id122" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Platform: Minimum Python version is now 3.9 (dropped 3.6, 3.7, 3.8)</p></li>
<li><p>Dependencies: Dramatically reduced core dependency count (10 → 5)</p>
<ul>
<li><p>Removed <code class="docutils literal notranslate"><span class="pre">requests</span></code>, <code class="docutils literal notranslate"><span class="pre">requests-toolbelt</span></code>, <code class="docutils literal notranslate"><span class="pre">rfc3986</span></code>, <code class="docutils literal notranslate"><span class="pre">whitenoise</span></code></p></li>
<li><p>Moved <code class="docutils literal notranslate"><span class="pre">apispec</span></code> and <code class="docutils literal notranslate"><span class="pre">marshmallow</span></code> to <code class="docutils literal notranslate"><span class="pre">openapi</span></code> optional extra</p></li>
<li><p>Replaced <code class="docutils literal notranslate"><span class="pre">rfc3986</span></code> with stdlib <code class="docutils literal notranslate"><span class="pre">urllib.parse</span></code></p></li>
<li><p>Replaced <code class="docutils literal notranslate"><span class="pre">requests-toolbelt</span></code> multipart decoder with <code class="docutils literal notranslate"><span class="pre">python-multipart</span></code></p></li>
<li><p>Replaced deprecated <code class="docutils literal notranslate"><span class="pre">starlette.middleware.wsgi</span></code> with <code class="docutils literal notranslate"><span class="pre">a2wsgi</span></code></p></li>
<li><p>Switched from WhiteNoise to ServeStatic</p></li>
</ul>
</li>
<li><p>Dependencies: Pinned <code class="docutils literal notranslate"><span class="pre">starlette[full]&gt;=0.40</span></code> (was unpinned)</p></li>
<li><p>GraphQL: Upgraded to <code class="docutils literal notranslate"><span class="pre">graphene&gt;=3</span></code> and <code class="docutils literal notranslate"><span class="pre">graphql-core&gt;=3.1</span></code>
(from <code class="docutils literal notranslate"><span class="pre">graphene&lt;3</span></code> and <code class="docutils literal notranslate"><span class="pre">graphql-server-core</span></code>, which is unmaintained)</p></li>
<li><p>GraphQL: Updated GraphiQL UI from 0.12.0 (2018) to 3.0.6 with React 18</p></li>
<li><p>Extensions: All of CLI-, GraphQL-, and OpenAPI-Support modules are
extensions now, found within the <code class="docutils literal notranslate"><span class="pre">responder.ext</span></code> module namespace.</p></li>
<li><p>Packaging: Migrated from <code class="docutils literal notranslate"><span class="pre">setup.py</span></code> to declarative <code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code></p></li>
</ul>
</section>
<section id="id123">
<h3>Removed<a class="headerlink" href="#id123" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Platform: Removed support for EOL Python 3.6, 3.7, 3.8</p></li>
<li><p>Status codes: Removed deprecated <code class="docutils literal notranslate"><span class="pre">resume_incomplete</span></code> and <code class="docutils literal notranslate"><span class="pre">resume</span></code>
aliases for HTTP 308 (marked for removal in 3.0)</p></li>
<li><p>CLI: <code class="docutils literal notranslate"><span class="pre">responder</span> <span class="pre">run</span> <span class="pre">--build</span></code> ceased to exist</p></li>
</ul>
</section>
<section id="id124">
<h3>Fixed<a class="headerlink" href="#id124" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Routing: Fixed dispatching <code class="docutils literal notranslate"><span class="pre">static_route=None</span></code> on Windows</p></li>
<li><p>uvicorn: <code class="docutils literal notranslate"><span class="pre">--debug</span></code> now maps to uvicorn’s <code class="docutils literal notranslate"><span class="pre">log_level</span> <span class="pre">=</span> <span class="pre">&quot;debug&quot;</span></code></p></li>
<li><p>Tests: Fixed deprecated httpx TestClient usage</p></li>
</ul>
</section>
</section>
<section id="v2-0-5-2019-12-15">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v2.0.4..v2.0.5">v2.0.5</a> - 2019-12-15<a class="headerlink" href="#v2-0-5-2019-12-15" title="Link to this heading"></a></h2>
<section id="id125">
<h3>Added<a class="headerlink" href="#id125" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Update requirements to support python 3.8</p></li>
</ul>
</section>
</section>
<section id="v2-0-4-2019-11-19">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v2.0.3..v2.0.4">v2.0.4</a> - 2019-11-19<a class="headerlink" href="#v2-0-4-2019-11-19" title="Link to this heading"></a></h2>
<section id="id126">
<h3>Fixed<a class="headerlink" href="#id126" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Fix static app resolving</p></li>
</ul>
</section>
</section>
<section id="v2-0-3-2019-09-20">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v2.0.2..v2.0.3">v2.0.3</a> - 2019-09-20<a class="headerlink" href="#v2-0-3-2019-09-20" title="Link to this heading"></a></h2>
<section id="id127">
<h3>Fixed<a class="headerlink" href="#id127" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Fix template conflicts</p></li>
</ul>
</section>
</section>
<section id="v2-0-2-2019-09-20">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v2.0.1..v2.0.2">v2.0.2</a> - 2019-09-20<a class="headerlink" href="#v2-0-2-2019-09-20" title="Link to this heading"></a></h2>
<section id="id128">
<h3>Fixed<a class="headerlink" href="#id128" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Fix template conflicts</p></li>
</ul>
</section>
</section>
<section id="v2-0-1-2019-09-20">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v2.0.0..v2.0.1">v2.0.1</a> - 2019-09-20<a class="headerlink" href="#v2-0-1-2019-09-20" title="Link to this heading"></a></h2>
<section id="id129">
<h3>Fixed<a class="headerlink" href="#id129" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Fix template import</p></li>
</ul>
</section>
</section>
<section id="v2-0-0-2019-09-19">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v1.3.2..v2.0.0">v2.0.0</a> - 2019-09-19<a class="headerlink" href="#v2-0-0-2019-09-19" title="Link to this heading"></a></h2>
<section id="id130">
<h3>Changed<a class="headerlink" href="#id130" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Refactor Router and Schema</p></li>
</ul>
</section>
</section>
<section id="v1-3-2-2019-08-15">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v1.3.1..v1.3.2">v1.3.2</a> - 2019-08-15<a class="headerlink" href="#v1-3-2-2019-08-15" title="Link to this heading"></a></h2>
<section id="id131">
<h3>Added<a class="headerlink" href="#id131" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>ASGI 3 support</p></li>
<li><p>CI tests for python 3.8-dev</p></li>
<li><p>Now requests have <code class="docutils literal notranslate"><span class="pre">state</span></code> a mapping object</p></li>
</ul>
</section>
<section id="id132">
<h3>Deprecated<a class="headerlink" href="#id132" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>ASGI 2</p></li>
</ul>
</section>
</section>
<section id="v1-3-1-2019-04-28">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v1.3.0..v1.3.1">v1.3.1</a> - 2019-04-28<a class="headerlink" href="#v1-3-1-2019-04-28" title="Link to this heading"></a></h2>
<section id="id133">
<h3>Added<a class="headerlink" href="#id133" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Route params Converters</p></li>
<li><p>Add search for documentation pages</p></li>
</ul>
</section>
<section id="id134">
<h3>Changed<a class="headerlink" href="#id134" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Bump dependencies</p></li>
</ul>
</section>
</section>
<section id="v1-3-0-2019-02-22">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v1.2.0..v1.3.0">v1.3.0</a> - 2019-02-22<a class="headerlink" href="#v1-3-0-2019-02-22" title="Link to this heading"></a></h2>
<section id="id135">
<h3>Fixed<a class="headerlink" href="#id135" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Versioning issue</p></li>
<li><p>Multiple cookies.</p></li>
<li><p>Whitenoise returns not found.</p></li>
<li><p>Other bugfixes.</p></li>
</ul>
</section>
<section id="id136">
<h3>Added<a class="headerlink" href="#id136" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Stream support via <code class="docutils literal notranslate"><span class="pre">resp.stream</span></code>.</p></li>
<li><p>Cookie directives via <code class="docutils literal notranslate"><span class="pre">resp.set_cookie</span></code>.</p></li>
<li><p>Add <code class="docutils literal notranslate"><span class="pre">resp.html</span></code> to send HTML.</p></li>
<li><p>Other improvements.</p></li>
</ul>
</section>
</section>
<section id="v1-1-3-2019-01-12">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v1.1.2..v1.1.3">v1.1.3</a> - 2019-01-12<a class="headerlink" href="#v1-1-3-2019-01-12" title="Link to this heading"></a></h2>
<section id="id137">
<h3>Changed<a class="headerlink" href="#id137" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Refactor <code class="docutils literal notranslate"><span class="pre">_route_for</span></code></p></li>
</ul>
</section>
<section id="id138">
<h3>Fixed<a class="headerlink" href="#id138" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Resolve startup/shutdwown events</p></li>
</ul>
</section>
</section>
<section id="v1-2-0-2018-12-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v1.1.3..v1.2.0">v1.2.0</a> - 2018-12-29<a class="headerlink" href="#v1-2-0-2018-12-29" title="Link to this heading"></a></h2>
<section id="id139">
<h3>Added<a class="headerlink" href="#id139" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Documentations</p></li>
</ul>
</section>
<section id="id140">
<h3>Changed<a class="headerlink" href="#id140" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Use Starlette’s LifeSpan middleware</p></li>
<li><p>Update denpendencies</p></li>
</ul>
</section>
<section id="id141">
<h3>Fixed<a class="headerlink" href="#id141" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Fix route.is_class_based</p></li>
<li><p>Fix test_500</p></li>
<li><p>Typos</p></li>
</ul>
</section>
</section>
<section id="v1-1-2-2018-11-11">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v1.1.1..v1.1.2">v1.1.2</a> - 2018-11-11<a class="headerlink" href="#v1-1-2-2018-11-11" title="Link to this heading"></a></h2>
<section id="id142">
<h3>Fixed<a class="headerlink" href="#id142" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Minor fixes for Open API</p></li>
<li><p>Typos</p></li>
</ul>
</section>
</section>
<section id="v1-1-1-2018-10-29">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v1.1.0..v1.1.1">v1.1.1</a> - 2018-10-29<a class="headerlink" href="#v1-1-1-2018-10-29" title="Link to this heading"></a></h2>
<section id="id143">
<h3>Changed<a class="headerlink" href="#id143" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Run sync views in a threadpoolexecutor.</p></li>
</ul>
</section>
</section>
<section id="v1-1-0-2018-10-27">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v1.0.5..v1.1.0">v1.1.0</a> - 2018-10-27<a class="headerlink" href="#v1-1-0-2018-10-27" title="Link to this heading"></a></h2>
<section id="id144">
<h3>Added<a class="headerlink" href="#id144" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Support for <code class="docutils literal notranslate"><span class="pre">before_request</span></code>.</p></li>
</ul>
</section>
</section>
<section id="v1-0-5-2018-10-27">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v1.0.4..v1.0.5">v1.0.5</a>- 2018-10-27<a class="headerlink" href="#v1-0-5-2018-10-27" title="Link to this heading"></a></h2>
<section id="id145">
<h3>Fixed<a class="headerlink" href="#id145" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Fix sessions.</p></li>
</ul>
</section>
</section>
<section id="v1-0-4-2018-10-27">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v1.0.3..v1.0.4">v1.0.4</a> - 2018-10-27<a class="headerlink" href="#v1-0-4-2018-10-27" title="Link to this heading"></a></h2>
<section id="id146">
<h3>Fixed<a class="headerlink" href="#id146" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Potential bufix for cookies.</p></li>
</ul>
</section>
</section>
<section id="v1-0-3-2018-10-27">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v1.0.2..v1.0.3">v1.0.3</a> - 2018-10-27<a class="headerlink" href="#v1-0-3-2018-10-27" title="Link to this heading"></a></h2>
<section id="id147">
<h3>Fixed<a class="headerlink" href="#id147" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Bugfix for redirects.</p></li>
</ul>
</section>
</section>
<section id="v1-0-2-2018-10-27">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v1.0.1..v1.0.2">v1.0.2</a> - 2018-10-27<a class="headerlink" href="#v1-0-2-2018-10-27" title="Link to this heading"></a></h2>
<section id="id148">
<h3>Changed<a class="headerlink" href="#id148" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Improvement for static file hosting.</p></li>
</ul>
</section>
</section>
<section id="v1-0-1-2018-10-26">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v1.0.0..v1.0.1">v1.0.1</a> - 2018-10-26<a class="headerlink" href="#v1-0-1-2018-10-26" title="Link to this heading"></a></h2>
<section id="id149">
<h3>Changed<a class="headerlink" href="#id149" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Improve cors configuration settings.</p></li>
</ul>
</section>
</section>
<section id="v1-0-0-2018-10-26">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.3.3..v1.0.0">v1.0.0</a> - 2018-10-26<a class="headerlink" href="#v1-0-0-2018-10-26" title="Link to this heading"></a></h2>
<section id="id150">
<h3>Changed<a class="headerlink" href="#id150" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Move GraphQL support into a built-in plugin.</p></li>
</ul>
</section>
</section>
<section id="v0-3-3-2018-10-25">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.3.2..v0.3.3">v0.3.3</a> - 2018-10-25<a class="headerlink" href="#v0-3-3-2018-10-25" title="Link to this heading"></a></h2>
<section id="id151">
<h3>Added<a class="headerlink" href="#id151" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>CORS support</p></li>
</ul>
</section>
<section id="id152">
<h3>Changed<a class="headerlink" href="#id152" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Improved exceptions.</p></li>
</ul>
</section>
</section>
<section id="v0-3-2-2018-10-25">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.3.1..v0.3.2">v0.3.2</a> - 2018-10-25<a class="headerlink" href="#v0-3-2-2018-10-25" title="Link to this heading"></a></h2>
<section id="id153">
<h3>Changed<a class="headerlink" href="#id153" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Subtle improvements.</p></li>
</ul>
</section>
</section>
<section id="v0-3-1-2018-10-24">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.3.0..v0.3.1">v0.3.1</a> - 2018-10-24<a class="headerlink" href="#v0-3-1-2018-10-24" title="Link to this heading"></a></h2>
<section id="id154">
<h3>Fixed<a class="headerlink" href="#id154" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Packaging fix.</p></li>
</ul>
</section>
</section>
<section id="v0-3-0-2018-10-24">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.2.3..v0.3.0">v0.3.0</a> - 2018-10-24<a class="headerlink" href="#v0-3-0-2018-10-24" title="Link to this heading"></a></h2>
<section id="id155">
<h3>Changed<a class="headerlink" href="#id155" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Interactive Documentation endpoint.</p></li>
<li><p>Minor improvements.</p></li>
</ul>
</section>
</section>
<section id="v0-2-3-2018-10-24">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.2.2..v0.2.3">v0.2.3</a> - 2018-10-24<a class="headerlink" href="#v0-2-3-2018-10-24" title="Link to this heading"></a></h2>
<section id="id156">
<h3>Changed<a class="headerlink" href="#id156" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Overall improvements.</p></li>
</ul>
</section>
</section>
<section id="v0-2-2-2018-10-23">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.2.1..v0.2.2">v0.2.2</a> - 2018-10-23<a class="headerlink" href="#v0-2-2-2018-10-23" title="Link to this heading"></a></h2>
<section id="id157">
<h3>Added<a class="headerlink" href="#id157" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Show traceback info when background tasks raise exceptions.</p></li>
</ul>
</section>
</section>
<section id="v0-2-1-2018-10-23">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.2.0..v0.2.1">v0.2.1</a> - 2018-10-23<a class="headerlink" href="#v0-2-1-2018-10-23" title="Link to this heading"></a></h2>
<section id="id158">
<h3>Added<a class="headerlink" href="#id158" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>api.requests.</p></li>
</ul>
</section>
</section>
<section id="v0-2-0-2018-10-22">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.1.6..v0.2.0">v0.2.0</a> - 2018-10-22<a class="headerlink" href="#v0-2-0-2018-10-22" title="Link to this heading"></a></h2>
<section id="id159">
<h3>Added<a class="headerlink" href="#id159" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>WebSocket support.</p></li>
</ul>
</section>
</section>
<section id="v0-1-6-2018-10-20">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.1.5..v0.1.6">v0.1.6</a> - 2018-10-20<a class="headerlink" href="#v0-1-6-2018-10-20" title="Link to this heading"></a></h2>
<section id="id160">
<h3>Added<a class="headerlink" href="#id160" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>500 support.</p></li>
</ul>
</section>
</section>
<section id="v0-1-5-2018-10-20">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.1.4..v0.1.5">v0.1.5</a> - 2018-10-20<a class="headerlink" href="#v0-1-5-2018-10-20" title="Link to this heading"></a></h2>
<section id="id161">
<h3>Added<a class="headerlink" href="#id161" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>File upload support</p></li>
</ul>
</section>
<section id="id162">
<h3>Changed<a class="headerlink" href="#id162" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Improvements to sequential media reading.</p></li>
</ul>
</section>
</section>
<section id="v0-1-4-2018-10-19">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.1.3..v0.1.4">v0.1.4</a> - 2018-10-19<a class="headerlink" href="#v0-1-4-2018-10-19" title="Link to this heading"></a></h2>
<section id="id163">
<h3>Fixed<a class="headerlink" href="#id163" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Stability.</p></li>
</ul>
</section>
</section>
<section id="v0-1-3-2018-10-18">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.1.2..v0.1.3">v0.1.3</a> - 2018-10-18<a class="headerlink" href="#v0-1-3-2018-10-18" title="Link to this heading"></a></h2>
<section id="id164">
<h3>Added<a class="headerlink" href="#id164" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Sessions support.</p></li>
</ul>
</section>
</section>
<section id="v0-1-2-2018-10-18">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.1.1..v0.1.2">v0.1.2</a> - 2018-10-18<a class="headerlink" href="#v0-1-2-2018-10-18" title="Link to this heading"></a></h2>
<section id="id165">
<h3>Added<a class="headerlink" href="#id165" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Cookies support.</p></li>
</ul>
</section>
</section>
<section id="v0-1-1-2018-10-17">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.1.0..v0.1.1">v0.1.1</a> - 2018-10-17<a class="headerlink" href="#v0-1-1-2018-10-17" title="Link to this heading"></a></h2>
<section id="id166">
<h3>Changed<a class="headerlink" href="#id166" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Default routes.</p></li>
</ul>
</section>
</section>
<section id="v0-1-0-2018-10-17">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.0.10..v0.1.0">v0.1.0</a> - 2018-10-17<a class="headerlink" href="#v0-1-0-2018-10-17" title="Link to this heading"></a></h2>
<section id="id167">
<h3>Added<a class="headerlink" href="#id167" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Prototype of static application support.</p></li>
</ul>
</section>
</section>
<section id="v0-0-10-2018-10-17">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.0.9..v0.0.10">v0.0.10</a> - 2018-10-17<a class="headerlink" href="#v0-0-10-2018-10-17" title="Link to this heading"></a></h2>
<section id="id168">
<h3>Fixed<a class="headerlink" href="#id168" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Bugfix for async class-based views.</p></li>
</ul>
</section>
</section>
<section id="v0-0-9-2018-10-17">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.0.8..v0.0.9">v0.0.9</a> - 2018-10-17<a class="headerlink" href="#v0-0-9-2018-10-17" title="Link to this heading"></a></h2>
<section id="id169">
<h3>Fixed<a class="headerlink" href="#id169" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Bugfix for async class-based views.</p></li>
</ul>
</section>
</section>
<section id="v0-0-8-2018-10-17">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.0.7..v0.0.8">v0.0.8</a> - 2018-10-17<a class="headerlink" href="#v0-0-8-2018-10-17" title="Link to this heading"></a></h2>
<section id="id170">
<h3>Added<a class="headerlink" href="#id170" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>GraphiQL Support.</p></li>
</ul>
</section>
<section id="id171">
<h3>Changed<a class="headerlink" href="#id171" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Improvement to route selection.</p></li>
</ul>
</section>
</section>
<section id="v0-0-7-2018-10-16">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.0.6..v0.0.7">v0.0.7</a> - 2018-10-16<a class="headerlink" href="#v0-0-7-2018-10-16" title="Link to this heading"></a></h2>
<section id="id172">
<h3>Changed<a class="headerlink" href="#id172" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Immutable Request object.</p></li>
</ul>
</section>
</section>
<section id="v0-0-6-2018-10-16">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.0.5..v0.0.6">v0.0.6</a> - 2018-10-16<a class="headerlink" href="#v0-0-6-2018-10-16" title="Link to this heading"></a></h2>
<section id="id173">
<h3>Added<a class="headerlink" href="#id173" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Ability to mount WSGI apps.</p></li>
<li><p>Supply content-type when serving up the schema.</p></li>
</ul>
</section>
</section>
<section id="v0-0-5-2018-10-15">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.0.4..v0.0.5">v0.0.5</a> - 2018-10-15<a class="headerlink" href="#v0-0-5-2018-10-15" title="Link to this heading"></a></h2>
<section id="id174">
<h3>Added<a class="headerlink" href="#id174" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>OpenAPI Schema support.</p></li>
<li><p>Safe load/dump yaml.</p></li>
</ul>
</section>
</section>
<section id="v0-0-4-2018-10-15">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.0.3..v0.0.4">v0.0.4</a> - 2018-10-15<a class="headerlink" href="#v0-0-4-2018-10-15" title="Link to this heading"></a></h2>
<section id="id175">
<h3>Added<a class="headerlink" href="#id175" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Asynchronous support for data uploads.</p></li>
</ul>
</section>
<section id="id176">
<h3>Fixed<a class="headerlink" href="#id176" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Bug fixes.</p></li>
</ul>
</section>
</section>
<section id="v0-0-3-2018-10-13">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.0.2..v0.0.3">v0.0.3</a> - 2018-10-13<a class="headerlink" href="#v0-0-3-2018-10-13" title="Link to this heading"></a></h2>
<section id="id177">
<h3>Fixed<a class="headerlink" href="#id177" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Bug fixes.</p></li>
</ul>
</section>
</section>
<section id="v0-0-2-2018-10-13">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.0.1..v0.0.2">v0.0.2</a> - 2018-10-13<a class="headerlink" href="#v0-0-2-2018-10-13" title="Link to this heading"></a></h2>
<section id="id178">
<h3>Changed<a class="headerlink" href="#id178" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Switch to ASGI/Starlette.</p></li>
</ul>
</section>
</section>
<section id="v0-0-1-2018-10-12">
<h2><a class="reference external" href="https://github.com/kennethreitz/responder/compare/v0.0.0..v0.0.1">v0.0.1</a> - 2018-10-12<a class="headerlink" href="#v0-0-1-2018-10-12" title="Link to this heading"></a></h2>
<section id="id179">
<h3>Added<a class="headerlink" href="#id179" title="Link to this heading"></a></h3>
<ul class="simple">
<li><p>Conception!</p></li>
</ul>
</section>
</section>
</section>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="Main">
<div class="sphinxsidebarwrapper"><p class="logo">
<a href="index.html">
<img class="logo" src="_static/responder.png" />
</a>
</p>
<p>
<strong>Responder</strong> — a familiar HTTP service framework for Python.
<br />
<small>v9.2.0</small>
</p>
<h3>Useful Links</h3>
<ul>
<li><a href="https://github.com/kennethreitz/responder">Responder @ GitHub</a></li>
<li><a href="https://pypi.org/project/responder/">Responder @ PyPI</a></li>
<li><a href="https://github.com/kennethreitz/responder/issues">Issue Tracker</a></li>
</ul><h3>Navigation</h3>
<p class="caption" role="heading"><span class="caption-text">User Guide</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="quickstart.html">Quick Start</a></li>
<li class="toctree-l1"><a class="reference internal" href="tour.html">Feature Tour</a></li>
<li class="toctree-l1"><a class="reference internal" href="examples.html">Examples</a></li>
<li class="toctree-l1"><a class="reference internal" href="routers.html">Composing Apps with Routers</a></li>
<li class="toctree-l1"><a class="reference internal" href="guide-config.html">Configuration</a></li>
<li class="toctree-l1"><a class="reference internal" href="clientgen.html">Generated Clients</a></li>
<li class="toctree-l1"><a class="reference internal" href="deployment.html">Deployment</a></li>
<li class="toctree-l1"><a class="reference internal" href="testing.html">Testing</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">Tutorials</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="tutorial-rest.html">Building a REST API</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-sqlalchemy.html">Using SQLAlchemy</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-auth.html">Authentication</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-websockets.html">WebSocket Tutorial</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-middleware.html">Writing Middleware</a></li>
<li class="toctree-l1"><a class="reference internal" href="tutorial-flask.html">Migrating from Flask</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">Reference</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="api.html">API Reference</a></li>
<li class="toctree-l1"><a class="reference internal" href="cli.html">Command Line Interface</a></li>
<li class="toctree-l1"><a class="reference internal" href="runtime-contracts.html">Runtime Contracts</a></li>
</ul>
<p class="caption" role="heading"><span class="caption-text">Project</span></p>
<ul class="current">
<li class="toctree-l1 current"><a class="current reference internal" href="#">Changelog</a></li>
<li class="toctree-l1"><a class="reference internal" href="migration-v9.html">Migrating to v9</a></li>
<li class="toctree-l1"><a class="reference internal" href="migration-v8.html">Migrating to v8</a></li>
<li class="toctree-l1"><a class="reference internal" href="migration-v7.html">Migrating to v7</a></li>
<li class="toctree-l1"><a class="reference internal" href="migration-v6.html">Migrating to v6</a></li>
<li class="toctree-l1"><a class="reference internal" href="migration-v5.html">Migrating to v5</a></li>
<li class="toctree-l1"><a class="reference internal" href="sandbox.html">Sandbox</a></li>
<li class="toctree-l1"><a class="reference internal" href="backlog.html">Backlog</a></li>
</ul>
<div class="relations">
<h3>Related Topics</h3>
<ul>
<li><a href="index.html">Documentation overview</a><ul>
<li>Previous: <a href="runtime-contracts.html" title="previous chapter">Runtime Contracts</a></li>
<li>Next: <a href="migration-v9.html" title="next chapter">Migrating to v9</a></li>
</ul></li>
</ul>
</div>
<search id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</search>
<script>document.getElementById('searchbox').style.display = "block"</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&#169;2018-2026, Kenneth Reitz.
|
<a href="_sources/changes.md.txt"
rel="nofollow">Page source</a>
</div>
<a href="https://github.com/kennethreitz/responder" class="github">
<img src="_static/forkme_right_darkblue.png" alt="Fork me on GitHub" class="github"/>
</a>
</body>
</html>