mirror of
https://github.com/kennethreitz/responder.git
synced 2026-10-24 05:59:12 +00:00
277 lines
24 KiB
HTML
277 lines
24 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>Generated Clients — 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">"Service"</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="s2">"1"</span><span class="p">,</span> <span class="n">openapi</span><span class="o">=</span><span class="s2">"3.0.2"</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">"/users/</span><span class="si">{user_id}</span><span class="s2">"</span><span class="p">,</span> <span class="n">operation_id</span><span class="o">=</span><span class="s2">"get_user"</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">"id"</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">"clients/service.py"</span><span class="p">,</span> <span class="n">class_name</span><span class="o">=</span><span class="s2">"ServiceClient"</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">"clients/service.ts"</span><span class="p">,</span>
|
||
<span class="n">class_name</span><span class="o">=</span><span class="s2">"ServiceClient"</span><span class="p">,</span>
|
||
<span class="n">language</span><span class="o">=</span><span class="s2">"typescript"</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">"clients/service.js"</span><span class="p">,</span> <span class="n">language</span><span class="o">=</span><span class="s2">"javascript"</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">"clients/service.rb"</span><span class="p">,</span> <span class="n">language</span><span class="o">=</span><span class="s2">"ruby"</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">"clients/ServiceClient.php"</span><span class="p">,</span> <span class="n">language</span><span class="o">=</span><span class="s2">"php"</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">-></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"><</span><span class="nx">ItemOut</span><span class="o">></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">"https://api.example.com"</span><span class="p">,</span> <span class="n">bearer_token</span><span class="o">=</span><span class="s2">"secret"</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">"id"</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">"name"</span><span class="p">:</span> <span class="s2">"tea"</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">"status"</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">"ServiceClient"</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">"ServiceClient"</span><span class="p">,</span>
|
||
<span class="n">language</span><span class="o">=</span><span class="s2">"typescript"</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">"ServiceClient"</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">"clients/service.py"</span><span class="p">,</span> <span class="n">class_name</span><span class="o">=</span><span class="s2">"ServiceClient"</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">"clients/service.ts"</span><span class="p">,</span>
|
||
<span class="n">class_name</span><span class="o">=</span><span class="s2">"ServiceClient"</span><span class="p">,</span>
|
||
<span class="n">language</span><span class="o">=</span><span class="s2">"typescript"</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>><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">
|
||
©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> |