mirror of
https://github.com/kennethreitz/responder.git
synced 2026-10-24 05:59:12 +00:00
405 lines
35 KiB
HTML
405 lines
35 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>Configuration — 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="Generated Clients" href="clientgen.html" />
|
||
<link rel="prev" title="Composing Apps with Routers" href="routers.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="configuration">
|
||
<h1>Configuration<a class="headerlink" href="#configuration" title="Link to this heading">¶</a></h1>
|
||
<p>Every application needs different settings for different environments —
|
||
debug mode in development, real secrets in production, different database
|
||
URLs for testing. This guide covers how to manage configuration cleanly.</p>
|
||
<section id="environment-variables">
|
||
<h2>Environment Variables<a class="headerlink" href="#environment-variables" title="Link to this heading">¶</a></h2>
|
||
<p>The simplest and most universal approach. Environment variables work
|
||
everywhere — locally, in Docker, on cloud platforms — and keep secrets
|
||
out of your source code:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
|
||
<span class="kn">import</span><span class="w"> </span><span class="nn">responder</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="c1"># RESPONDER_SECRET_KEY is picked up from the environment automatically</span>
|
||
<span class="n">debug</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">"DEBUG"</span><span class="p">,</span> <span class="s2">"false"</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s2">"true"</span><span class="p">,</span>
|
||
<span class="n">cors</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">"CORS_ENABLED"</span><span class="p">,</span> <span class="s2">"false"</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s2">"true"</span><span class="p">,</span>
|
||
<span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Some variables Responder reads automatically:</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">PORT</span></code> — when set, <code class="docutils literal notranslate"><span class="pre">api.run()</span></code> binds to <code class="docutils literal notranslate"><span class="pre">0.0.0.0</span></code> on this port
|
||
unless an explicit <code class="docutils literal notranslate"><span class="pre">port=</span></code> is also passed</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">RESPONDER_SECRET_KEY</span></code> — the signing key for sessions, used when you
|
||
don’t pass <code class="docutils literal notranslate"><span class="pre">secret_key=</span></code> explicitly (see <a class="reference internal" href="#secret-key">Secret Key</a> below)</p></li>
|
||
</ul>
|
||
<p>Set variables in your shell:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ export RESPONDER_SECRET_KEY="your-secret-here"
|
||
$ export DEBUG=true
|
||
$ python app.py
|
||
</pre></div>
|
||
</div>
|
||
<p>Or in a <code class="docutils literal notranslate"><span class="pre">.env</span></code> file (don’t commit this to git):</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">RESPONDER_SECRET_KEY</span><span class="o">=</span><span class="n">your</span><span class="o">-</span><span class="n">secret</span><span class="o">-</span><span class="n">here</span>
|
||
<span class="n">DEBUG</span><span class="o">=</span><span class="n">true</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="using-env-files">
|
||
<h2>Using .env Files<a class="headerlink" href="#using-env-files" title="Link to this heading">¶</a></h2>
|
||
<p>For local development, a <code class="docutils literal notranslate"><span class="pre">.env</span></code> file is convenient. Install
|
||
<code class="docutils literal notranslate"><span class="pre">python-dotenv</span></code> and load it at the top of your app:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ uv pip install python-dotenv
|
||
</pre></div>
|
||
</div>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">dotenv</span><span class="w"> </span><span class="kn">import</span> <span class="n">load_dotenv</span>
|
||
<span class="n">load_dotenv</span><span class="p">()</span>
|
||
|
||
<span class="kn">import</span><span class="w"> </span><span class="nn">responder</span>
|
||
|
||
<span class="c1"># Picks up RESPONDER_SECRET_KEY (and friends) from the loaded .env</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>
|
||
</pre></div>
|
||
</div>
|
||
<p>Add <code class="docutils literal notranslate"><span class="pre">.env</span></code> to your <code class="docutils literal notranslate"><span class="pre">.gitignore</span></code> — never commit secrets.</p>
|
||
</section>
|
||
<section id="configuration-class-pattern">
|
||
<h2>Configuration Class Pattern<a class="headerlink" href="#configuration-class-pattern" title="Link to this heading">¶</a></h2>
|
||
<p>For larger applications, a configuration class keeps things organized:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
|
||
|
||
<span class="k">class</span><span class="w"> </span><span class="nc">Config</span><span class="p">:</span>
|
||
<span class="n">SECRET_KEY</span> <span class="o">=</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">"RESPONDER_SECRET_KEY"</span><span class="p">)</span> <span class="c1"># None in dev → auto-generated</span>
|
||
<span class="n">DEBUG</span> <span class="o">=</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">"DEBUG"</span><span class="p">,</span> <span class="s2">"false"</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s2">"true"</span>
|
||
<span class="n">DATABASE_URL</span> <span class="o">=</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">"DATABASE_URL"</span><span class="p">,</span> <span class="s2">"sqlite:///dev.db"</span><span class="p">)</span>
|
||
<span class="n">CORS_ORIGINS</span> <span class="o">=</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">"CORS_ORIGINS"</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">","</span><span class="p">)</span>
|
||
|
||
<span class="n">config</span> <span class="o">=</span> <span class="n">Config</span><span class="p">()</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">debug</span><span class="o">=</span><span class="n">config</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">,</span>
|
||
<span class="n">secret_key</span><span class="o">=</span><span class="n">config</span><span class="o">.</span><span class="n">SECRET_KEY</span><span class="p">,</span>
|
||
<span class="n">cors</span><span class="o">=</span><span class="nb">bool</span><span class="p">(</span><span class="n">config</span><span class="o">.</span><span class="n">CORS_ORIGINS</span><span class="p">[</span><span class="mi">0</span><span class="p">]),</span>
|
||
<span class="n">cors_params</span><span class="o">=</span><span class="p">{</span><span class="s2">"allow_origins"</span><span class="p">:</span> <span class="n">config</span><span class="o">.</span><span class="n">CORS_ORIGINS</span><span class="p">},</span>
|
||
<span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This makes it easy to see all your settings in one place.</p>
|
||
</section>
|
||
<section id="secret-key">
|
||
<h2>Secret Key<a class="headerlink" href="#secret-key" title="Link to this heading">¶</a></h2>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">secret_key</span></code> signs cookie-based session data. If someone knows your
|
||
secret key, they can forge sessions and impersonate any user, so it must
|
||
be a real random value and stay out of source control.</p>
|
||
<p>Responder resolves the key in this order:</p>
|
||
<ol class="arabic simple">
|
||
<li><p>the explicit <code class="docutils literal notranslate"><span class="pre">secret_key=</span></code> argument</p></li>
|
||
<li><p>the <code class="docutils literal notranslate"><span class="pre">RESPONDER_SECRET_KEY</span></code> environment variable</p></li>
|
||
<li><p>otherwise, under the default <code class="docutils literal notranslate"><span class="pre">sessions="auto"</span></code>, a random key minted
|
||
per process at startup (with a loud warning)</p></li>
|
||
</ol>
|
||
<p>Generate one with:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ python -c "import secrets; print(secrets.token_urlsafe(32))"
|
||
</pre></div>
|
||
</div>
|
||
<p>Then supply it via the environment — no code required:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ export RESPONDER_SECRET_KEY="paste-the-generated-key-here"
|
||
</pre></div>
|
||
</div>
|
||
<p>or pass it 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">secret_key</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s2">"RESPONDER_SECRET_KEY"</span><span class="p">])</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>A few rules worth knowing:</p>
|
||
<ul class="simple">
|
||
<li><p><strong>Set a stable key in production.</strong> The auto-minted key (step 3) is
|
||
different in every worker and is regenerated on restart, so signed
|
||
session cookies stop validating across processes — users get logged
|
||
out. It’s fine for a single dev process, but any multi-worker or
|
||
multi-instance deploy needs a fixed <code class="docutils literal notranslate"><span class="pre">RESPONDER_SECRET_KEY</span></code>.</p></li>
|
||
<li><p><strong>The old public default is rejected.</strong> <code class="docutils literal notranslate"><span class="pre">secret_key="NOTASECRET"</span></code>
|
||
now raises <code class="docutils literal notranslate"><span class="pre">SessionConfigError</span></code> (a <code class="docutils literal notranslate"><span class="pre">ValueError</span></code> subclass from
|
||
<code class="docutils literal notranslate"><span class="pre">responder.ext.sessions</span></code>).</p></li>
|
||
<li><p><strong>Use at least 16 characters.</strong> Shorter keys are accepted but warn.</p></li>
|
||
<li><p><strong>Rotate it</strong> if it’s ever compromised — this invalidates all existing
|
||
sessions.</p></li>
|
||
</ul>
|
||
<div class="admonition note">
|
||
<p class="admonition-title">Note</p>
|
||
<p>A server-side session backend stores data on the server and keeps only
|
||
an opaque id in the cookie, so it doesn’t sign anything — <code class="docutils literal notranslate"><span class="pre">secret_key</span></code>
|
||
is irrelevant in that mode. See <a class="reference internal" href="#sessions">Sessions</a> below.</p>
|
||
</div>
|
||
</section>
|
||
<section id="sessions">
|
||
<span id="guide-config-sessions"></span><h2>Sessions<a class="headerlink" href="#sessions" title="Link to this heading">¶</a></h2>
|
||
<p>Sessions are enabled by default and secure out of the box. The
|
||
<code class="docutils literal notranslate"><span class="pre">sessions=</span></code> knob controls them:</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">"auto"</span></code> (default) — cookie sessions on; auto-mints an ephemeral key
|
||
if none is set (see <a class="reference internal" href="#secret-key">Secret Key</a>).</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">True</span></code> — strict mode: requires a real key via <code class="docutils literal notranslate"><span class="pre">secret_key=</span></code> or
|
||
<code class="docutils literal notranslate"><span class="pre">RESPONDER_SECRET_KEY</span></code>, and raises <code class="docutils literal notranslate"><span class="pre">SessionConfigError</span></code> if none is
|
||
found.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">False</span></code> — disables session middleware entirely. Accessing
|
||
<code class="docutils literal notranslate"><span class="pre">req.session</span></code> / <code class="docutils literal notranslate"><span class="pre">resp.session</span></code> then raises <code class="docutils literal notranslate"><span class="pre">RuntimeError</span></code>. Use
|
||
this for stateless APIs to silence the auto-key startup warning.</p></li>
|
||
</ul>
|
||
<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">sessions</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span> <span class="c1"># stateless service, no sessions</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The cookie and lifetime are tunable:</p>
|
||
<ul>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">session_https_only</span></code> (default <code class="docutils literal notranslate"><span class="pre">None</span></code>) — marks the cookie <code class="docutils literal notranslate"><span class="pre">Secure</span></code>
|
||
in production (<code class="docutils literal notranslate"><span class="pre">debug=False</span></code>) and not under <code class="docutils literal notranslate"><span class="pre">debug=True</span></code>. Behind a
|
||
TLS-terminating proxy this needs no action; pass <code class="docutils literal notranslate"><span class="pre">False</span></code> only if you
|
||
genuinely serve plain HTTP.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">session_same_site</span></code> (default <code class="docutils literal notranslate"><span class="pre">"lax"</span></code>) — <code class="docutils literal notranslate"><span class="pre">"strict"</span></code>, <code class="docutils literal notranslate"><span class="pre">"lax"</span></code>, or
|
||
<code class="docutils literal notranslate"><span class="pre">"none"</span></code>. <code class="docutils literal notranslate"><span class="pre">"none"</span></code> without a <code class="docutils literal notranslate"><span class="pre">Secure</span></code> cookie raises <code class="docutils literal notranslate"><span class="pre">ValueError</span></code>.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">session_cookie</span></code> (default <code class="docutils literal notranslate"><span class="pre">None</span></code> → <code class="docutils literal notranslate"><span class="pre">"session"</span></code>) — the cookie name.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">session_max_age</span></code> (default <code class="docutils literal notranslate"><span class="pre">1209600</span></code>, i.e. 14 days) — lifetime in
|
||
seconds.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">session_backend</span></code> (default <code class="docutils literal notranslate"><span class="pre">None</span></code>) — by default, session data is
|
||
stored in a signed cookie. Pass a backend to keep data server-side
|
||
instead, leaving only an opaque id in the cookie:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">responder.ext.sessions</span><span class="w"> </span><span class="kn">import</span> <span class="n">RedisSessionBackend</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">session_backend</span><span class="o">=</span><span class="n">RedisSessionBackend</span><span class="p">(</span><span class="n">url</span><span class="o">=</span><span class="s2">"redis://localhost:6379/0"</span><span class="p">),</span>
|
||
<span class="n">session_max_age</span><span class="o">=</span><span class="mi">3600</span><span class="p">,</span> <span class="c1"># 1 hour</span>
|
||
<span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Built-in backends are <code class="docutils literal notranslate"><span class="pre">MemorySessionBackend</span></code> (single-process, dev
|
||
only), <code class="docutils literal notranslate"><span class="pre">RedisSessionBackend</span></code>, and <code class="docutils literal notranslate"><span class="pre">AsyncRedisSessionBackend</span></code>
|
||
(preferred for async apps). With a backend, <code class="docutils literal notranslate"><span class="pre">secret_key</span></code> is unused.
|
||
Pairing <code class="docutils literal notranslate"><span class="pre">sessions=False</span></code> with a backend raises <code class="docutils literal notranslate"><span class="pre">ValueError</span></code>.</p>
|
||
</li>
|
||
</ul>
|
||
<p>For reading and writing session data in handlers — and rotating the
|
||
session id on login with <code class="docutils literal notranslate"><span class="pre">regenerate_session</span></code> — see
|
||
<a class="reference internal" href="tutorial-auth.html"><span class="doc">Authentication</span></a>.</p>
|
||
</section>
|
||
<section id="debug-mode">
|
||
<h2>Debug Mode<a class="headerlink" href="#debug-mode" title="Link to this heading">¶</a></h2>
|
||
<p>Debug mode controls error page behavior:</p>
|
||
<ul class="simple">
|
||
<li><p><strong>On</strong> (<code class="docutils literal notranslate"><span class="pre">debug=True</span></code>): detailed error pages with tracebacks. Never
|
||
use this in production — it exposes your source code.</p></li>
|
||
<li><p><strong>Off</strong> (<code class="docutils literal notranslate"><span class="pre">debug=False</span></code>): generic error pages. This is the default.</p></li>
|
||
</ul>
|
||
<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">debug</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># development only</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>A common pattern is to read it from the environment:</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">debug</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">"DEBUG"</span><span class="p">)</span> <span class="o">==</span> <span class="s2">"true"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Debug also relaxes session cookie security: with the default
|
||
<code class="docutils literal notranslate"><span class="pre">session_https_only=None</span></code>, session cookies are marked <code class="docutils literal notranslate"><span class="pre">Secure</span></code> in
|
||
production but not under <code class="docutils literal notranslate"><span class="pre">debug=True</span></code> (so they round-trip over plain
|
||
<code class="docutils literal notranslate"><span class="pre">http://</span></code> while you develop). See <a class="reference internal" href="#sessions">Sessions</a>.</p>
|
||
</section>
|
||
<section id="allowed-hosts">
|
||
<h2>Allowed Hosts<a class="headerlink" href="#allowed-hosts" title="Link to this heading">¶</a></h2>
|
||
<p>In production, always set <code class="docutils literal notranslate"><span class="pre">allowed_hosts</span></code> to prevent Host header
|
||
attacks. This should match the domain names your application serves:</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">allowed_hosts</span><span class="o">=</span><span class="p">[</span><span class="s2">"example.com"</span><span class="p">,</span> <span class="s2">"www.example.com"</span><span class="p">],</span>
|
||
<span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>In development, you can use <code class="docutils literal notranslate"><span class="pre">["*"]</span></code> (the default) or specific local
|
||
addresses:</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">allowed_hosts</span><span class="o">=</span><span class="p">[</span><span class="s2">"localhost"</span><span class="p">,</span> <span class="s2">"127.0.0.1"</span><span class="p">])</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="putting-it-all-together">
|
||
<h2>Putting It All Together<a class="headerlink" href="#putting-it-all-together" title="Link to this heading">¶</a></h2>
|
||
<p>A production-ready configuration setup:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
|
||
<span class="kn">from</span><span class="w"> </span><span class="nn">dotenv</span><span class="w"> </span><span class="kn">import</span> <span class="n">load_dotenv</span>
|
||
|
||
<span class="n">load_dotenv</span><span class="p">()</span>
|
||
|
||
<span class="kn">import</span><span class="w"> </span><span class="nn">responder</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="c1"># secret_key is read from RESPONDER_SECRET_KEY automatically</span>
|
||
<span class="n">debug</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">"DEBUG"</span><span class="p">,</span> <span class="s2">"false"</span><span class="p">)</span> <span class="o">==</span> <span class="s2">"true"</span><span class="p">,</span>
|
||
<span class="n">allowed_hosts</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">"ALLOWED_HOSTS"</span><span class="p">,</span> <span class="s2">"*"</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">","</span><span class="p">),</span>
|
||
<span class="c1"># Serving browser forms? Require a session-bound CSRF token on</span>
|
||
<span class="c1"># unsafe requests (see the tour's CSRF Protection section).</span>
|
||
<span class="n">csrf</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||
<span class="c1"># Behind nginx/Caddy/a load balancer, honor its Forwarded /</span>
|
||
<span class="c1"># X-Forwarded-* headers; leave off when directly exposed.</span>
|
||
<span class="n">trust_proxy_headers</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">"BEHIND_PROXY"</span><span class="p">)</span> <span class="o">==</span> <span class="s2">"true"</span><span class="p">,</span>
|
||
<span class="n">cors</span><span class="o">=</span><span class="nb">bool</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">"CORS_ORIGINS"</span><span class="p">)),</span>
|
||
<span class="n">cors_params</span><span class="o">=</span><span class="p">{</span>
|
||
<span class="s2">"allow_origins"</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s2">"CORS_ORIGINS"</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">","</span><span class="p">),</span>
|
||
<span class="s2">"allow_methods"</span><span class="p">:</span> <span class="p">[</span><span class="s2">"GET"</span><span class="p">,</span> <span class="s2">"POST"</span><span class="p">,</span> <span class="s2">"PUT"</span><span class="p">,</span> <span class="s2">"DELETE"</span><span class="p">],</span>
|
||
<span class="p">},</span>
|
||
<span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>With a <code class="docutils literal notranslate"><span class="pre">.env</span></code> file for local development:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">RESPONDER_SECRET_KEY</span><span class="o">=</span><span class="n">dev</span><span class="o">-</span><span class="n">secret</span><span class="o">-</span><span class="n">do</span><span class="o">-</span><span class="ow">not</span><span class="o">-</span><span class="n">use</span><span class="o">-</span><span class="ow">in</span><span class="o">-</span><span class="n">prod</span>
|
||
<span class="n">DEBUG</span><span class="o">=</span><span class="n">true</span>
|
||
<span class="n">ALLOWED_HOSTS</span><span class="o">=</span><span class="n">localhost</span><span class="p">,</span><span class="mf">127.0.0.1</span>
|
||
<span class="n">CORS_ORIGINS</span><span class="o">=</span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">localhost</span><span class="p">:</span><span class="mi">3000</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>And the same variables set properly in production (via your cloud
|
||
platform’s dashboard, Docker secrets, or a secrets manager) — with a real
|
||
<code class="docutils literal notranslate"><span class="pre">RESPONDER_SECRET_KEY</span></code> generated by <code class="docutils literal notranslate"><span class="pre">secrets.token_urlsafe(32)</span></code>.</p>
|
||
<p>For running this app under a real server, see <a class="reference internal" href="deployment.html"><span class="doc">Deployment</span></a>.</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 class="current">
|
||
<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 current"><a class="current reference internal" href="#">Configuration</a><ul>
|
||
<li class="toctree-l2"><a class="reference internal" href="#environment-variables">Environment Variables</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="#using-env-files">Using .env Files</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="#configuration-class-pattern">Configuration Class Pattern</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="#secret-key">Secret Key</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="#sessions">Sessions</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="#debug-mode">Debug Mode</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="#allowed-hosts">Allowed Hosts</a></li>
|
||
<li class="toctree-l2"><a class="reference internal" href="#putting-it-all-together">Putting It All Together</a></li>
|
||
</ul>
|
||
</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>
|
||
<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"><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="routers.html" title="previous chapter">Composing Apps with Routers</a></li>
|
||
<li>Next: <a href="clientgen.html" title="next chapter">Generated Clients</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/guide-config.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> |