Files
responder/tutorial-flask.html
T
2026-04-12 22:12:14 +00:00

306 lines
22 KiB
HTML
Raw 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 from Flask &#8212; responder 3.6.2 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=27fed22d" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
<link rel="stylesheet" type="text/css" href="_static/design-elements.e5416f61bae5d36adc6d722a2b6f8cff.css?v=452a8e97" />
<script src="_static/documentation_options.js?v=c0c9fa11"></script>
<script src="_static/doctools.js?v=9bcbadda"></script>
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
<script src="_static/copybutton.js?v=fd10adb8"></script>
<script>
</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="Configuration" href="guide-config.html" />
<link rel="prev" title="Writing Middleware" href="tutorial-middleware.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-from-flask">
<h1>Migrating from Flask<a class="headerlink" href="#migrating-from-flask" title="Link to this heading"></a></h1>
<p>If youre coming from Flask, youll find Responder familiar but different
in a few key ways. This guide maps Flask concepts to their Responder
equivalents and shows you how to translate common patterns.</p>
<section id="the-big-differences">
<h2>The Big Differences<a class="headerlink" href="#the-big-differences" title="Link to this heading"></a></h2>
<p><strong>No return values.</strong> In Flask, you return a response. In Responder, you
mutate it. This is the single biggest difference:</p>
<p>Flask:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">&quot;/&quot;</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">hello</span><span class="p">():</span>
<span class="k">return</span> <span class="s2">&quot;hello, world!&quot;</span>
</pre></div>
</div>
<p>Responder:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@api</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">&quot;/&quot;</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">hello</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">text</span> <span class="o">=</span> <span class="s2">&quot;hello, world!&quot;</span>
</pre></div>
</div>
<p><strong>Explicit request and response.</strong> Flask uses a global <code class="docutils literal notranslate"><span class="pre">request</span></code> object
(via thread-local magic). Responder passes <code class="docutils literal notranslate"><span class="pre">req</span></code> and <code class="docutils literal notranslate"><span class="pre">resp</span></code> explicitly.
No magic, no import needed — theyre right there in the function signature.</p>
<p><strong>ASGI, not WSGI.</strong> Flask runs on WSGI, which is synchronous. Responder
runs on ASGI, which supports async natively. You can still write sync
views — Responder runs them in a thread pool automatically.</p>
</section>
<section id="quick-reference">
<h2>Quick Reference<a class="headerlink" href="#quick-reference" title="Link to this heading"></a></h2>
<table class="docutils align-default">
<colgroup>
<col style="width: 40.0%" />
<col style="width: 60.0%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>Flask</p></th>
<th class="head"><p>Responder</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">Flask(__name__)</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">responder.API()</span></code></p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre">&quot;text&quot;</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">resp.text</span> <span class="pre">=</span> <span class="pre">&quot;text&quot;</span></code></p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre">jsonify(data)</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">resp.media</span> <span class="pre">=</span> <span class="pre">data</span></code></p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre">render_template(&quot;t.html&quot;,</span> <span class="pre">x=1)</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">resp.html</span> <span class="pre">=</span> <span class="pre">api.template(&quot;t.html&quot;,</span> <span class="pre">x=1)</span></code></p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">request.args[&quot;q&quot;]</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">req.params[&quot;q&quot;]</span></code></p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">request.json</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">req.media()</span></code></p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">request.form</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">await</span> <span class="pre">req.media(&quot;form&quot;)</span></code></p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">request.headers[&quot;X&quot;]</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">req.headers[&quot;X&quot;]</span></code></p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">request.method</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">req.method</span></code></p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">request.cookies[&quot;x&quot;]</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">req.cookies[&quot;x&quot;]</span></code></p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">session[&quot;x&quot;]</span> <span class="pre">=</span> <span class="pre">1</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">resp.session[&quot;x&quot;]</span> <span class="pre">=</span> <span class="pre">1</span></code></p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">abort(404)</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">resp.status_code</span> <span class="pre">=</span> <span class="pre">404</span></code></p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">redirect(&quot;/new&quot;)</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">api.redirect(resp,</span> <span class="pre">location=&quot;/new&quot;)</span></code></p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">&#64;app.before_request</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">&#64;api.route(before_request=True)</span></code></p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">&#64;app.errorhandler(404)</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">&#64;api.exception_handler(ValueError)</span></code></p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">app.run(debug=True)</span></code></p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">api.run(debug=True)</span></code></p></td>
</tr>
</tbody>
</table>
</section>
<section id="route-parameters">
<h2>Route Parameters<a class="headerlink" href="#route-parameters" title="Link to this heading"></a></h2>
<p>Flask uses <code class="docutils literal notranslate"><span class="pre">&lt;angle_brackets&gt;</span></code>. Responder uses <code class="docutils literal notranslate"><span class="pre">{curly_braces}</span></code>
with the same type convertor idea:</p>
<p>Flask:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">&quot;/users/&lt;int:user_id&gt;&quot;</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">get_user</span><span class="p">(</span><span class="n">user_id</span><span class="p">):</span>
<span class="k">return</span> <span class="n">jsonify</span><span class="p">({</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="n">user_id</span><span class="p">})</span>
</pre></div>
</div>
<p>Responder:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@api</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">&quot;/users/{user_id:int}&quot;</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">get_user</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">user_id</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="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="n">user_id</span><span class="p">}</span>
</pre></div>
</div>
<p>Note the <code class="docutils literal notranslate"><span class="pre">*</span></code> — route parameters are keyword-only arguments in
Responder. This makes the interface explicit about which arguments
come from the URL.</p>
</section>
<section id="json-apis">
<h2>JSON APIs<a class="headerlink" href="#json-apis" title="Link to this heading"></a></h2>
<p>Flask:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">&quot;/api/items&quot;</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;POST&quot;</span><span class="p">])</span>
<span class="k">def</span><span class="w"> </span><span class="nf">create_item</span><span class="p">():</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">json</span>
<span class="c1"># ... create item</span>
<span class="k">return</span> <span class="n">jsonify</span><span class="p">(</span><span class="n">item</span><span class="p">),</span> <span class="mi">201</span>
</pre></div>
</div>
<p>Responder:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@api</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">&quot;/api/items&quot;</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;POST&quot;</span><span class="p">])</span>
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">create_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="n">data</span> <span class="o">=</span> <span class="k">await</span> <span class="n">req</span><span class="o">.</span><span class="n">media</span><span class="p">()</span>
<span class="c1"># ... create item</span>
<span class="n">resp</span><span class="o">.</span><span class="n">media</span> <span class="o">=</span> <span class="n">item</span>
<span class="n">resp</span><span class="o">.</span><span class="n">status_code</span> <span class="o">=</span> <span class="mi">201</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">await</span></code> is needed because reading the request body is an async
I/O operation. This is more explicit than Flasks approach, and it
means the event loop isnt blocked while waiting for the body to arrive.</p>
</section>
<section id="templates">
<h2>Templates<a class="headerlink" href="#templates" title="Link to this heading"></a></h2>
<p>Both use Jinja2. The syntax is nearly identical:</p>
<p>Flask:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">&quot;/hello/&lt;name&gt;&quot;</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">hello</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
<span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s2">&quot;hello.html&quot;</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">name</span><span class="p">)</span>
</pre></div>
</div>
<p>Responder:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@api</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">&quot;/hello/</span><span class="si">{name}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">hello</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">name</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="n">api</span><span class="o">.</span><span class="n">template</span><span class="p">(</span><span class="s2">&quot;hello.html&quot;</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">name</span><span class="p">)</span>
</pre></div>
</div>
</section>
<section id="blueprints-route-groups">
<h2>Blueprints → Route Groups<a class="headerlink" href="#blueprints-route-groups" title="Link to this heading"></a></h2>
<p>Flask uses Blueprints to organize routes. Responder has route groups:</p>
<p>Flask:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">bp</span> <span class="o">=</span> <span class="n">Blueprint</span><span class="p">(</span><span class="s2">&quot;api&quot;</span><span class="p">,</span> <span class="vm">__name__</span><span class="p">,</span> <span class="n">url_prefix</span><span class="o">=</span><span class="s2">&quot;/api&quot;</span><span class="p">)</span>
<span class="nd">@bp</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">&quot;/users&quot;</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">list_users</span><span class="p">():</span>
<span class="k">return</span> <span class="n">jsonify</span><span class="p">([])</span>
<span class="n">app</span><span class="o">.</span><span class="n">register_blueprint</span><span class="p">(</span><span class="n">bp</span><span class="p">)</span>
</pre></div>
</div>
<p>Responder:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">api_v1</span> <span class="o">=</span> <span class="n">api</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="s2">&quot;/api&quot;</span><span class="p">)</span>
<span class="nd">@api_v1</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">&quot;/users&quot;</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">list_users</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">media</span> <span class="o">=</span> <span class="p">[]</span>
</pre></div>
</div>
</section>
<section id="gradual-migration">
<h2>Gradual Migration<a class="headerlink" href="#gradual-migration" title="Link to this heading"></a></h2>
<p>You dont have to migrate all at once. Responder can mount your existing
Flask app at a subroute, so you can move endpoints over one at a time:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">flask</span><span class="w"> </span><span class="kn">import</span> <span class="n">Flask</span>
<span class="n">flask_app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
<span class="c1"># Your existing Flask routes stay here</span>
<span class="nd">@flask_app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">&quot;/legacy&quot;</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="k">return</span> <span class="s2">&quot;old endpoint&quot;</span>
<span class="c1"># Mount Flask under /old, new routes go on Responder</span>
<span class="n">api</span><span class="o">.</span><span class="n">mount</span><span class="p">(</span><span class="s2">&quot;/old&quot;</span><span class="p">,</span> <span class="n">flask_app</span><span class="p">)</span>
<span class="nd">@api</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">&quot;/new&quot;</span><span class="p">)</span>
<span class="k">def</span><span class="w"> </span><span class="nf">new_endpoint</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">media</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;modern&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
</pre></div>
</div>
<p>Requests to <code class="docutils literal notranslate"><span class="pre">/old/legacy</span></code> go to Flask. Everything else goes to
Responder. When youve moved everything over, remove the mount.</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>v3.6.2</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>
<div>
<h3><a href="index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Migrating from Flask</a><ul>
<li><a class="reference internal" href="#the-big-differences">The Big Differences</a></li>
<li><a class="reference internal" href="#quick-reference">Quick Reference</a></li>
<li><a class="reference internal" href="#route-parameters">Route Parameters</a></li>
<li><a class="reference internal" href="#json-apis">JSON APIs</a></li>
<li><a class="reference internal" href="#templates">Templates</a></li>
<li><a class="reference internal" href="#blueprints-route-groups">Blueprints → Route Groups</a></li>
<li><a class="reference internal" href="#gradual-migration">Gradual Migration</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/tutorial-flask.rst.txt"
rel="nofollow">Page source</a>
</div>
</body>
</html>