Files
responder/migration-v5.html
2026-07-14 04:14:56 +00:00

281 lines
20 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>Migrating to Responder 5.0 &#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="Development Sandbox" href="sandbox.html" />
<link rel="prev" title="Migrating to Responder 6.0" href="migration-v6.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="migrating-to-responder-5-0">
<h1>Migrating to Responder 5.0<a class="headerlink" href="#migrating-to-responder-5-0" title="Link to this heading"></a></h1>
<p>Responder 5 layers fully type-driven request/response I/O, composable dependency
injection, plan-driven OpenAPI, secure-by-default sessions, and a deferred
middleware stack onto the unchanged <code class="docutils literal notranslate"><span class="pre">(req,</span> <span class="pre">resp)</span></code> core. The new typed features
are <strong>additive sugar</strong> — your existing handlers keep working — but v5 makes a
handful of deliberate breaking changes, listed here with the one-line fix.</p>
<section id="sessions">
<h2>Sessions<a class="headerlink" href="#sessions" title="Link to this heading"></a></h2>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head"><p>Change</p></th>
<th class="head"><p>What to do</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">secret_key</span></code> no longer defaults to the public <code class="docutils literal notranslate"><span class="pre">&quot;NOTASECRET&quot;</span></code>; <code class="docutils literal notranslate"><span class="pre">API()</span></code> mints a random per-process key</p></td>
<td><p>Set <code class="docutils literal notranslate"><span class="pre">API(secret_key=…)</span></code> or the <code class="docutils literal notranslate"><span class="pre">RESPONDER_SECRET_KEY</span></code> env var for stable, multi-worker sessions (a startup warning fires until you do).</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">API(secret_key=&quot;NOTASECRET&quot;)</span></code> raises <code class="docutils literal notranslate"><span class="pre">SessionConfigError</span></code></p></td>
<td><p>Generate a real key: <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">-c</span> <span class="pre">&quot;import</span> <span class="pre">secrets;</span> <span class="pre">print(secrets.token_urlsafe(32))&quot;</span></code>.</p></td>
</tr>
<tr class="row-even"><td><p>Session cookies are <code class="docutils literal notranslate"><span class="pre">Secure</span></code> by default in production</p></td>
<td><p>No action behind a TLS proxy; pass <code class="docutils literal notranslate"><span class="pre">session_https_only=False</span></code> only if you genuinely serve plain HTTP (e.g. local dev, tests).</p></td>
</tr>
<tr class="row-odd"><td><p><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 <code class="docutils literal notranslate"><span class="pre">RuntimeError</span></code> when <code class="docutils literal notranslate"><span class="pre">sessions=False</span></code></p></td>
<td><p>Re-enable sessions, or stop reading the session under the explicit opt-out.</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">sessions=True</span></code> with no key raises</p></td>
<td><p>Provide a key, or use <code class="docutils literal notranslate"><span class="pre">sessions=&quot;auto&quot;</span></code> (the default) to auto-generate an ephemeral one.</p></td>
</tr>
</tbody>
</table>
<p>Server-side sessions now slide their TTL via <code class="docutils literal notranslate"><span class="pre">touch</span></code>/<code class="docutils literal notranslate"><span class="pre">atouch</span></code> on read-only
requests (no behavior change for you; implement <code class="docutils literal notranslate"><span class="pre">touch</span></code> on a custom backend for
the cheaper path).</p>
</section>
<section id="req-method-is-uppercase">
<h2><code class="docutils literal notranslate"><span class="pre">req.method</span></code> is uppercase<a class="headerlink" href="#req-method-is-uppercase" title="Link to this heading"></a></h2>
<p><code class="docutils literal notranslate"><span class="pre">req.method</span></code> now returns <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).
For one deprecation cycle it 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 <strong>with a <code class="docutils literal notranslate"><span class="pre">DeprecationWarning</span></code></strong>. Uppercase your literals.</p>
<p>Hash-based membership is the one thing the shim can’t save: <code class="docutils literal notranslate"><span class="pre">req.method</span> <span class="pre">in</span> <span class="pre">{&quot;get&quot;}</span></code>
and <code class="docutils literal notranslate"><span class="pre">{&quot;get&quot;:</span> <span class="pre">…}[req.method]</span></code> miss silently — use <code class="docutils literal notranslate"><span class="pre">==</span></code>, a tuple/list, or
uppercase keys.</p>
</section>
<section id="middleware-errors">
<h2>Middleware &amp; errors<a class="headerlink" href="#middleware-errors" title="Link to this heading"></a></h2>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head"><p>Change</p></th>
<th class="head"><p>What to do</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">API.app</span></code> is a lazily-built read-only property, not a writable attribute</p></td>
<td><p>Mutate via <code class="docutils literal notranslate"><span class="pre">api.add_middleware(Cls,</span> <span class="pre">**opts)</span></code> (now valid post-construction), or wrap the API object: <code class="docutils literal notranslate"><span class="pre">asgi</span> <span class="pre">=</span> <span class="pre">MyMiddleware(api)</span></code>.</p></td>
</tr>
<tr class="row-odd"><td><p>User middleware now sits inside <code class="docutils literal notranslate"><span class="pre">ServerErrorMiddleware</span></code></p></td>
<td><p>Its exceptions are now caught and rendered as <code class="docutils literal notranslate"><span class="pre">500</span></code>s. To wrap <em>everything</em>, wrap the API object instead of <code class="docutils literal notranslate"><span class="pre">add_middleware</span></code>.</p></td>
</tr>
<tr class="row-even"><td><p>Session writes are not persisted on an unhandled <code class="docutils literal notranslate"><span class="pre">500</span></code></p></td>
<td><p>Persist explicitly before raising if you need it.</p></td>
</tr>
</tbody>
</table>
<p><code class="docutils literal notranslate"><span class="pre">X-Request-ID</span></code> now appears on error/<code class="docutils literal notranslate"><span class="pre">500</span></code> responses too, and
<code class="docutils literal notranslate"><span class="pre">api.add_exception_handler(exc_or_status,</span> <span class="pre">handler)</span></code> is now a first-class method.</p>
</section>
<section id="typed-handler-i-o">
<h2>Typed handler I/O<a class="headerlink" href="#typed-handler-i-o" title="Link to this heading"></a></h2>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head"><p>Change</p></th>
<th class="head"><p>What to do</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p>A Pydantic return annotation (<code class="docutils literal notranslate"><span class="pre">-&gt;</span> <span class="pre">Model</span></code>) is now honored as <code class="docutils literal notranslate"><span class="pre">response_model</span></code></p></td>
<td><p>Make the returned dict conform, or pass <code class="docutils literal notranslate"><span class="pre">&#64;api.route(...,</span> <span class="pre">response_model=False)</span></code> <em>(if you don’t want validation)</em>.</p></td>
</tr>
<tr class="row-odd"><td><p>A body-model parameter beats a same-named dependency</p></td>
<td><p>Rename the dependency, or give the parameter a default.</p></td>
</tr>
<tr class="row-even"><td><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>/<code class="docutils literal notranslate"><span class="pre">Path</span></code> are reserved top-level names</p></td>
<td><p>Only affects <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">responder</span> <span class="pre">import</span> <span class="pre">*</span></code>; explicit imports are unaffected.</p></td>
</tr>
</tbody>
</table>
<p>New: <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">token:</span> <span class="pre">str</span> <span class="pre">=</span> <span class="pre">Header(None))</span></code>
injects validated query params, headers, cookies, and path params.</p>
</section>
<section id="dependency-injection">
<h2>Dependency injection<a class="headerlink" href="#dependency-injection" title="Link to this heading"></a></h2>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head"><p>Change</p></th>
<th class="head"><p>What to do</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p>A provider receives 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</p></td>
<td><p>Rename a nonstandard request parameter to <code class="docutils literal notranslate"><span class="pre">req</span></code>, or annotate it <code class="docutils literal notranslate"><span class="pre">Request</span></code>. A sole-unnamed-param provider still works for one cycle (with a <code class="docutils literal notranslate"><span class="pre">DeprecationWarning</span></code>).</p></td>
</tr>
<tr class="row-odd"><td><p><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></td>
<td><p>Rename any dependency registered under these.</p></td>
</tr>
<tr class="row-even"><td><p>Misconfigured graphs raise <code class="docutils literal notranslate"><span class="pre">DependencyError</span></code> subclasses</p></td>
<td><p>Cycles, unknown params, and scope violations now surface as <code class="docutils literal notranslate"><span class="pre">DependencyCycleError</span></code> / <code class="docutils literal notranslate"><span class="pre">DependencyResolutionError</span></code> / <code class="docutils literal notranslate"><span class="pre">DependencyScopeError</span></code>.</p></td>
</tr>
</tbody>
</table>
<p>New: a provider can depend on other providers (recursive, memoized,
reverse-topological teardown, cycle detection).</p>
</section>
<section id="openapi">
<h2>OpenAPI<a class="headerlink" href="#openapi" title="Link to this heading"></a></h2>
<table class="docutils align-default">
<thead>
<tr class="row-odd"><th class="head"><p>Change</p></th>
<th class="head"><p>What to do</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p>Routes without a docstring/model now appear in the schema</p></td>
<td><p>Pass <code class="docutils literal notranslate"><span class="pre">&#64;api.route(...,</span> <span class="pre">include_in_schema=False)</span></code> to hide a route (schema/docs/static/metrics are auto-excluded).</p></td>
</tr>
<tr class="row-odd"><td><p>Docstring YAML is deep-merged onto a generated base</p></td>
<td><p>Fully-specified docstrings are unaffected; the generated parameters/request/response are added underneath.</p></td>
</tr>
</tbody>
</table>
<p>The spec is now generated from each route’s methods, 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, with an automatic <code class="docutils literal notranslate"><span class="pre">422</span></code> for validating routes.</p>
</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"><a class="reference internal" href="changes.html">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 current"><a class="current reference internal" href="#">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="migration-v6.html" title="previous chapter">Migrating to Responder 6.0</a></li>
<li>Next: <a href="sandbox.html" title="next chapter">Development Sandbox</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/migration-v5.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>