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

277 lines
24 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en" data-content_root="./">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Generated Clients &#8212; responder 9.2.0 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=5ecbeea2" />
<link rel="stylesheet" type="text/css" href="_static/basic.css?v=b08954a9" />
<link rel="stylesheet" type="text/css" href="_static/alabaster.css?v=eb4102c5" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
<link rel="stylesheet" type="text/css" href="_static/sphinx-design.min.css?v=95c83b7e" />
<link rel="stylesheet" type="text/css" href="_static/design-elements.e5416f61bae5d36adc6d722a2b6f8cff.css?v=452a8e97" />
<script src="_static/documentation_options.js?v=e8b940be"></script>
<script src="_static/doctools.js?v=fd6eb6e6"></script>
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
<script src="_static/copybutton.js?v=fd10adb8"></script>
<script>
</script>
<script src="_static/design-tabs.js?v=f930bc37"></script>
<script src="_static/design-elements.bbdccc18c4abea9397628f9fea3d48c2.js?v=03c7770e"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Deployment" href="deployment.html" />
<link rel="prev" title="Configuration" href="guide-config.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="generated-clients">
<h1>Generated Clients<a class="headerlink" href="#generated-clients" title="Link to this heading"></a></h1>
<p>Responder can generate small API clients from the OpenAPI schema it already
builds from your routes, markers, and Pydantic models.</p>
<p>Enable OpenAPI on your app, then write a Python client module:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></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="n">title</span><span class="o">=</span><span class="s2">&quot;Service&quot;</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="s2">&quot;1&quot;</span><span class="p">,</span> <span class="n">openapi</span><span class="o">=</span><span class="s2">&quot;3.0.2&quot;</span><span class="p">)</span>
<span class="nd">@api</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;/users/</span><span class="si">{user_id}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">operation_id</span><span class="o">=</span><span class="s2">&quot;get_user&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="nb">int</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>
<span class="n">api</span><span class="o">.</span><span class="n">generate_client</span><span class="p">(</span><span class="s2">&quot;clients/service.py&quot;</span><span class="p">,</span> <span class="n">class_name</span><span class="o">=</span><span class="s2">&quot;ServiceClient&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Use <code class="docutils literal notranslate"><span class="pre">language=</span></code> to generate clients for other ecosystems:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">api</span><span class="o">.</span><span class="n">generate_client</span><span class="p">(</span>
<span class="s2">&quot;clients/service.ts&quot;</span><span class="p">,</span>
<span class="n">class_name</span><span class="o">=</span><span class="s2">&quot;ServiceClient&quot;</span><span class="p">,</span>
<span class="n">language</span><span class="o">=</span><span class="s2">&quot;typescript&quot;</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">api</span><span class="o">.</span><span class="n">generate_client</span><span class="p">(</span><span class="s2">&quot;clients/service.js&quot;</span><span class="p">,</span> <span class="n">language</span><span class="o">=</span><span class="s2">&quot;javascript&quot;</span><span class="p">)</span>
<span class="n">api</span><span class="o">.</span><span class="n">generate_client</span><span class="p">(</span><span class="s2">&quot;clients/service.rb&quot;</span><span class="p">,</span> <span class="n">language</span><span class="o">=</span><span class="s2">&quot;ruby&quot;</span><span class="p">)</span>
<span class="n">api</span><span class="o">.</span><span class="n">generate_client</span><span class="p">(</span><span class="s2">&quot;clients/ServiceClient.php&quot;</span><span class="p">,</span> <span class="n">language</span><span class="o">=</span><span class="s2">&quot;php&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Supported languages are <code class="docutils literal notranslate"><span class="pre">python</span></code>, <code class="docutils literal notranslate"><span class="pre">javascript</span></code>, <code class="docutils literal notranslate"><span class="pre">typescript</span></code>, <code class="docutils literal notranslate"><span class="pre">ruby</span></code>,
and <code class="docutils literal notranslate"><span class="pre">php</span></code>. The generated modules have no Responder runtime dependency. Python,
Ruby, and PHP clients use standard libraries for HTTP calls; JavaScript and
TypeScript clients use <code class="docutils literal notranslate"><span class="pre">fetch</span></code>.</p>
<p>When your OpenAPI schema includes component models, Python and TypeScript
clients also generate model types. Request bodies use the request model type,
and methods return the documented success response type:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">ItemIn</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
<span class="k">class</span><span class="w"> </span><span class="nc">ItemOut</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
<span class="nb">id</span><span class="p">:</span> <span class="nb">int</span>
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
<span class="k">def</span><span class="w"> </span><span class="nf">create_item</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">body</span><span class="p">:</span> <span class="n">ItemIn</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">ItemOut</span><span class="p">:</span>
<span class="o">...</span>
</pre></div>
</div>
<div class="highlight-typescript notranslate"><div class="highlight"><pre><span></span><span class="k">export</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="nx">ItemIn</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">name</span><span class="o">:</span><span class="w"> </span><span class="kt">string</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">export</span><span class="w"> </span><span class="kd">interface</span><span class="w"> </span><span class="nx">ItemOut</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">id</span><span class="o">:</span><span class="w"> </span><span class="kt">number</span><span class="p">;</span>
<span class="w"> </span><span class="nx">name</span><span class="o">:</span><span class="w"> </span><span class="kt">string</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">create_item</span><span class="p">(</span><span class="nx">body</span><span class="o">:</span><span class="w"> </span><span class="kt">ItemIn</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="kc">null</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="o">:</span><span class="w"> </span><span class="nb">Promise</span><span class="o">&lt;</span><span class="nx">ItemOut</span><span class="o">&gt;</span>
</pre></div>
</div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">clients.service</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServiceClient</span>
<span class="n">client</span> <span class="o">=</span> <span class="n">ServiceClient</span><span class="p">(</span><span class="s2">&quot;https://api.example.com&quot;</span><span class="p">,</span> <span class="n">bearer_token</span><span class="o">=</span><span class="s2">&quot;secret&quot;</span><span class="p">)</span>
<span class="n">user</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_user</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
</pre></div>
</div>
<p>For Python tests, pass Responder’s in-process test client. This lets your
generated client exercise the app without a listening socket:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">client</span> <span class="o">=</span> <span class="n">ServiceClient</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">api</span><span class="o">.</span><span class="n">requests</span><span class="p">)</span>
<span class="k">assert</span> <span class="n">client</span><span class="o">.</span><span class="n">get_user</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span> <span class="o">==</span> <span class="p">{</span><span class="s2">&quot;id&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">}</span>
</pre></div>
</div>
<p>For a fuller example, <code class="docutils literal notranslate"><span class="pre">examples/atelier.py</span></code> is the canonical contract app:
the test suite validates its OpenAPI document, generates a Python client from
it, and drives that client against the in-process API.</p>
<p>Python, JavaScript, and TypeScript clients can also validate JSON payloads at
runtime. Validation is off by default; pass <code class="docutils literal notranslate"><span class="pre">validate=True</span></code> in Python or
<code class="docutils literal notranslate"><span class="pre">validate:</span> <span class="pre">true</span></code> in JavaScript/TypeScript to check outgoing request bodies and
successful responses against the generated OpenAPI schemas:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">client</span> <span class="o">=</span> <span class="n">ServiceClient</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">api</span><span class="o">.</span><span class="n">requests</span><span class="p">,</span> <span class="n">validate</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">client</span><span class="o">.</span><span class="n">create_item</span><span class="p">({</span><span class="s2">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;tea&quot;</span><span class="p">})</span>
</pre></div>
</div>
<p>If validation fails, the client raises <code class="docutils literal notranslate"><span class="pre">APIValidationError</span></code> with the schema
path that failed, such as <code class="docutils literal notranslate"><span class="pre">response.id</span> <span class="pre">expected</span> <span class="pre">integer</span></code>.</p>
<p>When a request fails and the server returns <code class="docutils literal notranslate"><span class="pre">application/problem+json</span></code>, the
generated <code class="docutils literal notranslate"><span class="pre">APIError</span></code> exposes the parsed payload as <code class="docutils literal notranslate"><span class="pre">problem</span></code>. Python clients
also provide <code class="docutils literal notranslate"><span class="pre">title</span></code>, <code class="docutils literal notranslate"><span class="pre">detail</span></code>, and <code class="docutils literal notranslate"><span class="pre">errors</span></code> convenience attributes:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">try</span><span class="p">:</span>
<span class="n">client</span><span class="o">.</span><span class="n">get_user</span><span class="p">(</span><span class="mi">404</span><span class="p">)</span>
<span class="k">except</span> <span class="n">APIError</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span>
<span class="k">assert</span> <span class="n">exc</span><span class="o">.</span><span class="n">problem</span><span class="p">[</span><span class="s2">&quot;status&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="mi">404</span>
<span class="nb">print</span><span class="p">(</span><span class="n">exc</span><span class="o">.</span><span class="n">title</span><span class="p">)</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">API.generate_client(...)</span></code> returns source code when no path is supplied:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">source</span> <span class="o">=</span> <span class="n">api</span><span class="o">.</span><span class="n">generate_client</span><span class="p">(</span><span class="n">class_name</span><span class="o">=</span><span class="s2">&quot;ServiceClient&quot;</span><span class="p">)</span>
<span class="n">typescript</span> <span class="o">=</span> <span class="n">api</span><span class="o">.</span><span class="n">generate_client</span><span class="p">(</span>
<span class="n">class_name</span><span class="o">=</span><span class="s2">&quot;ServiceClient&quot;</span><span class="p">,</span>
<span class="n">language</span><span class="o">=</span><span class="s2">&quot;typescript&quot;</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
</div>
<p>The lower-level helpers are available from <code class="xref py py-mod docutils literal notranslate"><span class="pre">responder.ext.clientgen</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">responder.ext.clientgen</span><span class="w"> </span><span class="kn">import</span> <span class="n">generate_client</span><span class="p">,</span> <span class="n">write_client</span>
<span class="n">source</span> <span class="o">=</span> <span class="n">generate_client</span><span class="p">(</span><span class="n">api</span><span class="o">.</span><span class="n">openapi</span><span class="p">,</span> <span class="n">class_name</span><span class="o">=</span><span class="s2">&quot;ServiceClient&quot;</span><span class="p">)</span>
<span class="n">write_client</span><span class="p">(</span><span class="n">api</span><span class="o">.</span><span class="n">openapi</span><span class="p">,</span> <span class="s2">&quot;clients/service.py&quot;</span><span class="p">,</span> <span class="n">class_name</span><span class="o">=</span><span class="s2">&quot;ServiceClient&quot;</span><span class="p">)</span>
<span class="n">write_client</span><span class="p">(</span>
<span class="n">api</span><span class="o">.</span><span class="n">openapi</span><span class="p">,</span>
<span class="s2">&quot;clients/service.ts&quot;</span><span class="p">,</span>
<span class="n">class_name</span><span class="o">=</span><span class="s2">&quot;ServiceClient&quot;</span><span class="p">,</span>
<span class="n">language</span><span class="o">=</span><span class="s2">&quot;typescript&quot;</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
</div>
<p>The command-line interface can generate clients from an import target too:</p>
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>responder<span class="w"> </span>client<span class="w"> </span>app:api<span class="w"> </span>&gt;<span class="w"> </span>clients/service.py
responder<span class="w"> </span>client<span class="w"> </span>--lang<span class="w"> </span>typescript<span class="w"> </span>--class-name<span class="w"> </span>ServiceClient<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--output<span class="w"> </span>clients/service.ts<span class="w"> </span>app:api
</pre></div>
</div>
<p>Generated clients include:</p>
<ul class="simple">
<li><p>method signatures generated from path and query parameters,</p></li>
<li><p>JSON request-body support,</p></li>
<li><p>bearer, basic, and API-key header helpers,</p></li>
<li><p>structured <code class="docutils literal notranslate"><span class="pre">APIError</span></code> exceptions for non-2xx responses,</p></li>
<li><p>opt-in <code class="docutils literal notranslate"><span class="pre">APIValidationError</span></code> checks for JSON request/response schemas,</p></li>
<li><p>real HTTP transport for network calls,</p></li>
<li><p>Python <code class="docutils literal notranslate"><span class="pre">TypedDict</span></code> models and TypeScript interfaces for OpenAPI components,</p></li>
<li><p>typed Python and TypeScript parameters/returns where schemas are available,</p></li>
<li><p>a Python-only <code class="docutils literal notranslate"><span class="pre">session=</span></code> hook for Starlette/httpx-style clients in tests.</p></li>
</ul>
</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"><a class="reference internal" href="guide-config.html">Configuration</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">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="guide-config.html" title="previous chapter">Configuration</a></li>
<li>Next: <a href="deployment.html" title="next chapter">Deployment</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/clientgen.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>