mirror of
https://github.com/kennethreitz/responder.git
synced 2026-10-24 05:59:12 +00:00
355 lines
33 KiB
HTML
355 lines
33 KiB
HTML
<!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 v9 — 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 v8" href="migration-v8.html" />
|
||
<link rel="prev" title="Changelog" href="changes.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-v9">
|
||
<h1>Migrating to v9<a class="headerlink" href="#migrating-to-v9" title="Link to this heading">¶</a></h1>
|
||
<p>Responder 9.0 makes the v8.1 deprecation path the default behavior. Most
|
||
apps only need small cleanup: use the supported test-client helpers, pass
|
||
explicit route endpoints, and rely on precision-preserving JSON defaults.</p>
|
||
<p>The compatibility switches documented below are explicit and quiet. They are
|
||
there for apps that need to keep 8.x behavior while migrating.</p>
|
||
<p>Run your test suite with warnings surfaced to find any unrelated deprecations:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">python</span> <span class="o">-</span><span class="n">W</span> <span class="n">error</span><span class="p">::</span><span class="ne">DeprecationWarning</span> <span class="o">-</span><span class="n">m</span> <span class="n">pytest</span>
|
||
</pre></div>
|
||
</div>
|
||
<section id="typed-response-contracts-in-9-1">
|
||
<h2>Typed response contracts in 9.1<a class="headerlink" href="#typed-response-contracts-in-9-1" title="Link to this heading">¶</a></h2>
|
||
<p>Responder 9.1 treats every supported return annotation as an enforced response
|
||
contract. This now includes Pydantic 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. The same type drives runtime validation and serialization, OpenAPI,
|
||
and generated-client types:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@api</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"/items"</span><span class="p">)</span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">list_items</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">resp</span><span class="p">)</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="n">ItemOut</span><span class="p">]:</span>
|
||
<span class="k">return</span> <span class="n">rows</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Earlier releases inferred only a narrower set of shapes. A route that returned
|
||
data inconsistent with a generic or scalar annotation may now fail closed with
|
||
<code class="docutils literal notranslate"><span class="pre">500</span></code>. Fix the returned value to match the annotation, or explicitly retain
|
||
mutation-only/unchecked behavior while migrating:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@api</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"/legacy"</span><span class="p">,</span> <span class="n">response_model</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">legacy</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">resp</span><span class="p">)</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="n">ItemOut</span><span class="p">]:</span>
|
||
<span class="n">resp</span><span class="o">.</span><span class="n">media</span> <span class="o">=</span> <span class="n">build_legacy_payload</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Unresolvable or unsupported return annotations now produce a registration
|
||
warning naming the route and the <code class="docutils literal notranslate"><span class="pre">response_model=False</span></code> escape hatch.</p>
|
||
<p>Alternate statuses can declare their own runtime and OpenAPI contracts through
|
||
<code class="docutils literal notranslate"><span class="pre">responses=</span></code>. Return the body and status together, or assign <code class="docutils literal notranslate"><span class="pre">resp</span></code> as
|
||
usual:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">NotFound</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
|
||
<span class="n">detail</span><span class="p">:</span> <span class="nb">str</span>
|
||
|
||
<span class="nd">@api</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"/items/</span><span class="si">{item_id}</span><span class="s2">"</span><span class="p">,</span> <span class="n">responses</span><span class="o">=</span><span class="p">{</span><span class="mi">404</span><span class="p">:</span> <span class="n">NotFound</span><span class="p">})</span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">get_item</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">resp</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">item_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">ItemOut</span><span class="p">:</span>
|
||
<span class="n">item</span> <span class="o">=</span> <span class="n">find_item</span><span class="p">(</span><span class="n">item_id</span><span class="p">)</span>
|
||
<span class="k">if</span> <span class="n">item</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="n">NotFound</span><span class="p">(</span><span class="n">detail</span><span class="o">=</span><span class="s2">"Item not found"</span><span class="p">),</span> <span class="mi">404</span>
|
||
<span class="k">return</span> <span class="n">item</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Use <code class="docutils literal notranslate"><span class="pre">{"model":</span> <span class="pre">NotFound,</span> <span class="pre">"description":</span> <span class="pre">"..."}</span></code> as the response value
|
||
when the generated OpenAPI response needs a custom description, headers, or
|
||
other metadata.</p>
|
||
</section>
|
||
<section id="multipart-uploads-stream-to-disk">
|
||
<h2>Multipart uploads stream to disk<a class="headerlink" href="#multipart-uploads-stream-to-disk" title="Link to this heading">¶</a></h2>
|
||
<p>Multipart bodies now parse incrementally as they arrive: file parts spool to
|
||
temporary files (rolling to disk past ~1 MB) instead of being buffered in
|
||
RAM. Nothing changes in how you read uploads — <code class="docutils literal notranslate"><span class="pre">File()</span></code> markers,
|
||
<code class="docutils literal notranslate"><span class="pre">req.media("files")</span></code>, and <code class="docutils literal notranslate"><span class="pre">req.media("form")</span></code> all work as before, and
|
||
<code class="docutils literal notranslate"><span class="pre">UploadFile.save()</span></code> copies disk-to-disk in chunks.</p>
|
||
<p>Two consequences of the body no longer being buffered:</p>
|
||
<ul class="simple">
|
||
<li><p><strong>The raw body is consumed by the parse.</strong> <code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">req.content</span></code> after a
|
||
multipart parse raises a <code class="docutils literal notranslate"><span class="pre">RuntimeError</span></code> (previously it returned the full
|
||
buffered body). If a handler needs both the raw bytes and the parsed form,
|
||
await <code class="docutils literal notranslate"><span class="pre">req.content</span></code> <em>first</em> — parsing then falls back to the buffered
|
||
body, exactly like 8.x. 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 have
|
||
the form parsed before they run, so the raw multipart body is not available
|
||
to them at all (this matches Starlette and FastAPI).</p></li>
|
||
<li><p><strong>Text fields share the streaming parser’s limits.</strong> <code class="docutils literal notranslate"><span class="pre">req.media("form")</span></code>
|
||
on a multipart body now goes through the same parse as <code class="docutils literal notranslate"><span class="pre">media("files")</span></code>:
|
||
at most 1000 parts and 1 MB per text field (oversized or malformed bodies
|
||
get a <code class="docutils literal notranslate"><span class="pre">400</span></code>). Text fields with invalid UTF-8 are now decoded lossily
|
||
instead of being silently dropped.</p></li>
|
||
</ul>
|
||
</section>
|
||
<section id="request-bodies-are-capped-at-100-mib-by-default">
|
||
<h2>Request bodies are capped at 100 MiB by default<a class="headerlink" href="#request-bodies-are-capped-at-100-mib-by-default" title="Link to this heading">¶</a></h2>
|
||
<p><code class="docutils literal notranslate"><span class="pre">max_request_size</span></code> now defaults to 100 MiB instead of unlimited; larger
|
||
bodies get a <code class="docutils literal notranslate"><span class="pre">413</span></code>. The cap is enforced chunk-by-chunk on the wire, and
|
||
since multipart uploads spool to disk, raising it does not raise memory
|
||
use:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">api</span> <span class="o">=</span> <span class="n">responder</span><span class="o">.</span><span class="n">API</span><span class="p">(</span><span class="n">max_request_size</span><span class="o">=</span><span class="mi">5</span> <span class="o">*</span> <span class="mi">1024</span><span class="o">**</span><span class="mi">3</span><span class="p">)</span> <span class="c1"># allow 5 GiB uploads</span>
|
||
<span class="n">api</span> <span class="o">=</span> <span class="n">responder</span><span class="o">.</span><span class="n">API</span><span class="p">(</span><span class="n">max_request_size</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span> <span class="c1"># pre-9.0 unlimited</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="rate-limit-errors-use-problem-details">
|
||
<h2>Rate-limit errors use Problem Details<a class="headerlink" href="#rate-limit-errors-use-problem-details" title="Link to this heading">¶</a></h2>
|
||
<p>With the default <code class="docutils literal notranslate"><span class="pre">API(problem_details=True)</span></code>, the rate limiter’s
|
||
<code class="docutils literal notranslate"><span class="pre">429</span> <span class="pre">Too</span> <span class="pre">Many</span> <span class="pre">Requests</span></code> and fail-closed-backend <code class="docutils literal notranslate"><span class="pre">503</span> <span class="pre">Service</span>
|
||
<span class="pre">Unavailable</span></code> responses now use the same RFC 9457
|
||
<code class="docutils literal notranslate"><span class="pre">application/problem+json</span></code> envelope as framework-generated errors:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">{</span><span class="s2">"type"</span><span class="p">:</span> <span class="s2">"about:blank"</span><span class="p">,</span> <span class="s2">"title"</span><span class="p">:</span> <span class="s2">"Too Many Requests"</span><span class="p">,</span>
|
||
<span class="s2">"status"</span><span class="p">:</span> <span class="mi">429</span><span class="p">,</span> <span class="s2">"detail"</span><span class="p">:</span> <span class="s2">"Rate limit exceeded."</span><span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Previously the body was <code class="docutils literal notranslate"><span class="pre">{"error":</span> <span class="pre">"rate</span> <span class="pre">limit</span> <span class="pre">exceeded"}</span></code> — clients that
|
||
parse the <code class="docutils literal notranslate"><span class="pre">error</span></code> key need updating (or key off the status code and
|
||
<code class="docutils literal notranslate"><span class="pre">Retry-After</span></code>/<code class="docutils literal notranslate"><span class="pre">X-RateLimit-*</span></code> headers, which are unchanged). To keep the
|
||
legacy body shape while migrating, pass <code class="docutils literal notranslate"><span class="pre">API(problem_details=False)</span></code>,
|
||
which also keeps the legacy shape for all framework errors.</p>
|
||
</section>
|
||
<section id="trust-proxy-headers-now-rewrites-the-connection-scope">
|
||
<h2><code class="docutils literal notranslate"><span class="pre">trust_proxy_headers</span></code> now rewrites the connection scope<a class="headerlink" href="#trust-proxy-headers-now-rewrites-the-connection-scope" title="Link to this heading">¶</a></h2>
|
||
<p>In 8.x, <code class="docutils literal notranslate"><span class="pre">API(trust_proxy_headers=True)</span></code> only changed the client IP recorded
|
||
by <code class="docutils literal notranslate"><span class="pre">enable_logging</span></code>. It now honors the full set of forwarding headers —
|
||
RFC 7239 <code class="docutils literal notranslate"><span class="pre">Forwarded</span></code>, plus <code class="docutils literal notranslate"><span class="pre">X-Forwarded-Proto</span></code>/<code class="docutils literal notranslate"><span class="pre">-Host</span></code>/<code class="docutils literal notranslate"><span class="pre">-For</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">X-Real-IP</span></code> — rewriting the request’s scheme, host, and client address for
|
||
every layer: HTTPS detection, redirects, URL building, trusted-host
|
||
validation, and rate-limit keys. If you enabled the flag purely for logging,
|
||
logged IPs are unchanged; the scheme/host handling simply becomes correct
|
||
behind your proxy. Leave the flag off (the default) when Responder is
|
||
directly exposed.</p>
|
||
</section>
|
||
<section id="api-session-was-removed">
|
||
<h2><code class="docutils literal notranslate"><span class="pre">api.session()</span></code> was removed<a class="headerlink" href="#api-session-was-removed" title="Link to this heading">¶</a></h2>
|
||
<p>The legacy test-client accessor <code class="docutils literal notranslate"><span class="pre">api.session()</span></code> has been removed. Use the
|
||
<a class="reference internal" href="api.html#responder.API.requests" title="responder.API.requests"><code class="xref py py-attr docutils literal notranslate"><span class="pre">requests</span></code></a> property instead:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">r</span> <span class="o">=</span> <span class="n">api</span><span class="o">.</span><span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"http://;/hello"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If you relied on <code class="docutils literal notranslate"><span class="pre">session(base_url=...)</span></code> for a custom base URL, construct
|
||
the client through the supported helper:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">client</span> <span class="o">=</span> <span class="n">api</span><span class="o">.</span><span class="n">test_client</span><span class="p">(</span><span class="n">base_url</span><span class="o">=</span><span class="s2">"http://testserver"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="explicit-port-now-wins-over-port">
|
||
<h2>Explicit <code class="docutils literal notranslate"><span class="pre">port=</span></code> now wins over <code class="docutils literal notranslate"><span class="pre">PORT</span></code><a class="headerlink" href="#explicit-port-now-wins-over-port" title="Link to this heading">¶</a></h2>
|
||
<p>When <code class="docutils literal notranslate"><span class="pre">api.run()</span></code> / <code class="docutils literal notranslate"><span class="pre">api.serve()</span></code> receive both an explicit <code class="docutils literal notranslate"><span class="pre">port=</span></code> and
|
||
a conflicting <code class="docutils literal notranslate"><span class="pre">PORT</span></code> environment variable, the explicit argument wins:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># PORT=9000 in the environment:</span>
|
||
<span class="n">api</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">port</span><span class="o">=</span><span class="mi">8000</span><span class="p">)</span> <span class="c1"># binds 8000</span>
|
||
<span class="n">api</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">port</span><span class="o">=</span><span class="mi">9000</span><span class="p">)</span> <span class="c1"># binds 9000</span>
|
||
<span class="n">api</span><span class="o">.</span><span class="n">run</span><span class="p">()</span> <span class="c1"># binds 9000</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>To keep environment-first behavior, resolve the environment yourself:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">api</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">port</span><span class="o">=</span><span class="nb">int</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"PORT"</span><span class="p">,</span> <span class="mi">8000</span><span class="p">)))</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>or use the legacy compatibility switch while migrating:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">api</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">port</span><span class="o">=</span><span class="mi">8000</span><span class="p">,</span> <span class="n">port_precedence</span><span class="o">=</span><span class="s2">"env"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="bare-add-route-static-fallback">
|
||
<h2>Bare <code class="docutils literal notranslate"><span class="pre">add_route()</span></code> static fallback<a class="headerlink" href="#bare-add-route-static-fallback" title="Link to this heading">¶</a></h2>
|
||
<p>Calling <code class="docutils literal notranslate"><span class="pre">api.add_route(route)</span></code> with no endpoint now raises by default
|
||
instead of implicitly registering a <em>default</em> route that serves
|
||
<code class="docutils literal notranslate"><span class="pre">static/index.html</span></code> for every unmatched request. Pass an endpoint
|
||
explicitly instead:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">pathlib</span>
|
||
|
||
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">spa</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">resp</span><span class="p">):</span>
|
||
<span class="n">resp</span><span class="o">.</span><span class="n">html</span> <span class="o">=</span> <span class="p">(</span><span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="s2">"static"</span><span class="p">)</span> <span class="o">/</span> <span class="s2">"index.html"</span><span class="p">)</span><span class="o">.</span><span class="n">read_text</span><span class="p">()</span>
|
||
|
||
<span class="n">api</span><span class="o">.</span><span class="n">add_route</span><span class="p">(</span><span class="s2">"/"</span><span class="p">,</span> <span class="n">spa</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Static <em>assets</em> are unaffected: the <code class="docutils literal notranslate"><span class="pre">static_dir</span></code> / <code class="docutils literal notranslate"><span class="pre">static_route</span></code> mount
|
||
keeps working as-is.</p>
|
||
<p>If you need the old fallback while migrating, opt in explicitly:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">api</span> <span class="o">=</span> <span class="n">responder</span><span class="o">.</span><span class="n">API</span><span class="p">(</span><span class="n">implicit_static_fallback</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="decimal-serializes-as-a-json-string">
|
||
<h2><code class="docutils literal notranslate"><span class="pre">Decimal</span></code> serializes as a JSON string<a class="headerlink" href="#decimal-serializes-as-a-json-string" title="Link to this heading">¶</a></h2>
|
||
<p>Assigning a bare <code class="xref py py-class docutils literal notranslate"><span class="pre">decimal.Decimal</span></code> to <code class="docutils literal notranslate"><span class="pre">resp.media</span></code> now serializes it
|
||
as a JSON string, preserving precision.</p>
|
||
<p>Choose a representation explicitly when your API contract needs a number:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">resp</span><span class="o">.</span><span class="n">media</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"price"</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">total</span><span class="p">)}</span> <span class="c1"># exact, v9's default</span>
|
||
<span class="n">resp</span><span class="o">.</span><span class="n">media</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"price"</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">total</span><span class="p">)}</span> <span class="c1"># lossy, JSON number</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>or keep floats everywhere with the compatibility flag or a custom encoder:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">api</span> <span class="o">=</span> <span class="n">responder</span><span class="o">.</span><span class="n">API</span><span class="p">(</span><span class="n">json_decimal</span><span class="o">=</span><span class="s2">"float"</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">encoder</span><span class="p">(</span><span class="n">obj</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">decimal</span><span class="o">.</span><span class="n">Decimal</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="nb">float</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
|
||
<span class="k">raise</span> <span class="ne">TypeError</span> <span class="c1"># fall back to the built-in conversions</span>
|
||
|
||
<span class="n">api</span> <span class="o">=</span> <span class="n">responder</span><span class="o">.</span><span class="n">API</span><span class="p">(</span><span class="n">encoder</span><span class="o">=</span><span class="n">encoder</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="graphql-400-with-partial-data">
|
||
<h2>GraphQL: <code class="docutils literal notranslate"><span class="pre">400</span></code> with partial data<a class="headerlink" href="#graphql-400-with-partial-data" title="Link to this heading">¶</a></h2>
|
||
<p>The GraphQL extension now returns HTTP <code class="docutils literal notranslate"><span class="pre">200</span></code> for execution results that
|
||
contain both <code class="docutils literal notranslate"><span class="pre">data</span></code> and <code class="docutils literal notranslate"><span class="pre">errors</span></code> (a <em>partial</em> result, e.g. one resolver
|
||
failed while others succeeded). Per the <a class="reference external" href="https://graphql.github.io/graphql-over-http/">GraphQL-over-HTTP specification</a>, these are well-formed
|
||
GraphQL responses.</p>
|
||
<p>Requests that produce <em>no</em> data (validation or request errors) keep their
|
||
<code class="docutils literal notranslate"><span class="pre">400</span></code>. Inspect the <code class="docutils literal notranslate"><span class="pre">errors</span></code> key of the response body instead of relying
|
||
on the status code alone:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">api</span><span class="o">.</span><span class="n">graphql</span><span class="p">(</span><span class="s2">"/graph"</span><span class="p">,</span> <span class="n">schema</span><span class="o">=</span><span class="n">schema</span><span class="p">)</span>
|
||
|
||
<span class="n">result</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/graph"</span><span class="p">,</span> <span class="n">json</span><span class="o">=</span><span class="p">{</span><span class="s2">"query"</span><span class="p">:</span> <span class="n">query</span><span class="p">})</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
|
||
<span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"errors"</span><span class="p">):</span>
|
||
<span class="o">...</span> <span class="c1"># handle errors, regardless of HTTP status</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>To preserve the legacy partial-data status while migrating, pass:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">api</span><span class="o">.</span><span class="n">graphql</span><span class="p">(</span><span class="s2">"/graph"</span><span class="p">,</span> <span class="n">schema</span><span class="o">=</span><span class="n">schema</span><span class="p">,</span> <span class="n">partial_data_status</span><span class="o">=</span><span class="mi">400</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</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 current"><a class="current reference internal" href="#">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="changes.html" title="previous chapter">Changelog</a></li>
|
||
<li>Next: <a href="migration-v8.html" title="next chapter">Migrating to v8</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">
|
||
©2018-2026, Kenneth Reitz.
|
||
|
||
|
|
||
<a href="_sources/migration-v9.rst.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> |