feat(standards): codify codegen, ship generic Tier-B infra, add get_app_template + prompts; fix docs:// regressions
P0: fix doc:// -> docs:// across standards src/server/registry and regenerate stale mongo-ops bundle. P1: build recipe + spec-first routing now document the openapi-first codegen fast path (models/routes with --inject-request/--package). P4: CRUD template documents the model-vs-document id rule (BaseDocument owns id). P5: authless guidance (omit security keys). P6: template gains generic infra (http_cache, keyed SSE bus, KV port+in-memory+Redis), interfaces/openapi.py + .dockerignore + generic build test registered as components, and a get_app_template tool; genericity matrix marks LLM pool + human-in-loop as reference-app patterns. P7: intake/build/start_app/trial prompts. P8: template ships tests/integration/test_openapi_app_builds.py. Rebuilt standards + openapi-first bundles and re-collected.
This commit is contained in:
@@ -761,7 +761,7 @@ that enforces OpenAPI as the single source of truth for a FastAPI service.</p>
|
||||
Python handler function.
|
||||
- Handlers are plain Python callables (no FastAPI decorators).
|
||||
- FastAPI route registration is derived exclusively from the spec.
|
||||
- FastAPI's autogenerated OpenAPI schema is fully overridden.
|
||||
- FastAPI's autogenerated OpenAPI schema is fully overridden.
|
||||
</code></pre></div></td></tr></table></div>
|
||||
<p><strong>Responsibilities:</strong></p>
|
||||
<div class="language-text highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">1</span>
|
||||
@@ -924,7 +924,7 @@ handlers).</p>
|
||||
- All routes are derived from the provided OpenAPI specification,
|
||||
and each ``operationId`` is mapped to a Python function in the
|
||||
supplied routes module.
|
||||
- Auth dependencies are auto-injected from the spec's
|
||||
- Auth dependencies are auto-injected from the spec's
|
||||
``securitySchemes`` and per-operation ``security`` fields.
|
||||
</code></pre></div></td></tr></table></div>
|
||||
<p><strong>Guarantees:</strong></p>
|
||||
@@ -955,9 +955,9 @@ handlers).</p>
|
||||
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="kn">import</span><span class="w"> </span><span class="nn">app.routes</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">routes</span>
|
||||
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3"></a>
|
||||
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="n">app</span> <span class="o">=</span> <span class="n">OpenAPIFirstApp</span><span class="p">(</span>
|
||||
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5"></a> <span class="n">openapi_path</span><span class="o">=</span><span class="s2">"app/openapi.json"</span><span class="p">,</span>
|
||||
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5"></a> <span class="n">openapi_path</span><span class="o">=</span><span class="s2">"app/openapi.json"</span><span class="p">,</span>
|
||||
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6"></a> <span class="n">routes_module</span><span class="o">=</span><span class="n">routes</span><span class="p">,</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7"></a> <span class="n">title</span><span class="o">=</span><span class="s2">"Example Service"</span><span class="p">,</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7"></a> <span class="n">title</span><span class="o">=</span><span class="s2">"Example Service"</span><span class="p">,</span>
|
||||
</span><span id="__span-0-8"><a id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="p">)</span>
|
||||
</span></code></pre></div></td></tr></table></div>
|
||||
</details>
|
||||
|
||||
@@ -937,16 +937,16 @@ missing/duplicate, or required parameters are missing.</p>
|
||||
<span class="normal"><a href="#__codelineno-0-15">15</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-16">16</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">openapi_first</span><span class="w"> </span><span class="kn">import</span> <span class="n">loader</span><span class="p">,</span> <span class="n">client</span>
|
||||
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2"></a>
|
||||
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="n">spec</span> <span class="o">=</span> <span class="n">loader</span><span class="o">.</span><span class="n">load_openapi</span><span class="p">(</span><span class="s2">"openapi.yaml"</span><span class="p">)</span>
|
||||
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="n">spec</span> <span class="o">=</span> <span class="n">loader</span><span class="o">.</span><span class="n">load_openapi</span><span class="p">(</span><span class="s2">"openapi.yaml"</span><span class="p">)</span>
|
||||
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4"></a>
|
||||
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="n">api</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">OpenAPIClient</span><span class="p">(</span>
|
||||
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6"></a> <span class="n">spec</span><span class="o">=</span><span class="n">spec</span><span class="p">,</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7"></a> <span class="n">base_url</span><span class="o">=</span><span class="s2">"http://localhost:8000"</span><span class="p">,</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7"></a> <span class="n">base_url</span><span class="o">=</span><span class="s2">"http://localhost:8000"</span><span class="p">,</span>
|
||||
</span><span id="__span-0-8"><a id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="p">)</span>
|
||||
</span><span id="__span-0-9"><a id="__codelineno-0-9" name="__codelineno-0-9"></a>
|
||||
</span><span id="__span-0-10"><a id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="c1"># Call operationId: getUser</span>
|
||||
</span><span id="__span-0-11"><a id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="n">response</span> <span class="o">=</span> <span class="n">api</span><span class="o">.</span><span class="n">getUser</span><span class="p">(</span>
|
||||
</span><span id="__span-0-12"><a id="__codelineno-0-12" name="__codelineno-0-12"></a> <span class="n">path_params</span><span class="o">=</span><span class="p">{</span><span class="s2">"user_id"</span><span class="p">:</span> <span class="mi">123</span><span class="p">}</span>
|
||||
</span><span id="__span-0-12"><a id="__codelineno-0-12" name="__codelineno-0-12"></a> <span class="n">path_params</span><span class="o">=</span><span class="p">{</span><span class="s2">"user_id"</span><span class="p">:</span> <span class="mi">123</span><span class="p">}</span>
|
||||
</span><span id="__span-0-13"><a id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="p">)</span>
|
||||
</span><span id="__span-0-14"><a id="__codelineno-0-14" name="__codelineno-0-14"></a>
|
||||
</span><span id="__span-0-15"><a id="__codelineno-0-15" name="__codelineno-0-15"></a><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">status_code</span><span class="p">)</span>
|
||||
|
||||
@@ -762,21 +762,25 @@ definitions.</p>
|
||||
<span class="normal"><a href="#__codelineno-0-4">4</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-5">5</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-6">6</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-7">7</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="nf">generate_routes</span><span class="p">(</span>
|
||||
<span class="normal"><a href="#__codelineno-0-7">7</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-8">8</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-9">9</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="nf">generate_routes</span><span class="p">(</span>
|
||||
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2"></a> <span class="n">spec_path</span><span class="p">:</span> <span class="n">Path</span><span class="p">,</span>
|
||||
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3"></a> <span class="n">output_dir</span><span class="p">:</span> <span class="n">Path</span><span class="p">,</span>
|
||||
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4"></a> <span class="o">*</span><span class="p">,</span>
|
||||
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5"></a> <span class="n">use_models</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
|
||||
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6"></a> <span class="n">models_module</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">"models"</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="p">)</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="n">Path</span><span class="p">]</span>
|
||||
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6"></a> <span class="n">models_module</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">"models"</span><span class="p">,</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7"></a> <span class="n">inject_request</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
|
||||
</span><span id="__span-0-8"><a id="__codelineno-0-8" name="__codelineno-0-8"></a> <span class="n">package</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
|
||||
</span><span id="__span-0-9"><a id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="p">)</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="n">Path</span><span class="p">]</span>
|
||||
</span></code></pre></div></td></tr></table></div>
|
||||
|
||||
<div class="doc doc-contents ">
|
||||
|
||||
<p>Generate route handler stubs from an OpenAPI specification.</p>
|
||||
<p>Creates one <code><resource>.py</code> file per resource in <em>output_dir</em>.
|
||||
Resources are derived from the first path segment (e.g. <code>/pets</code>
|
||||
and <code>/pets/{id}</code> both group under <code>pets</code>).</p>
|
||||
<p>Creates one route module per resource in <em>output_dir</em>. Resources are
|
||||
derived from the first path segment (e.g. <code>/pets</code> and <code>/pets/{id}</code>
|
||||
both group under <code>pets</code>) and sanitized to valid module identifiers.</p>
|
||||
|
||||
|
||||
<p><span class="doc-section-title">Parameters:</span></p>
|
||||
@@ -849,6 +853,36 @@ for request-body schemas referenced via <code>$ref</code>.</p>
|
||||
<code>'models'</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="doc-section-item">
|
||||
<td><code>inject_request</code></td>
|
||||
<td>
|
||||
<code>bool</code>
|
||||
</td>
|
||||
<td>
|
||||
<div class="doc-md-description">
|
||||
<p>If <code>True</code>, prepend <code>request: Request</code> to every handler so the
|
||||
stub can later resolve services from <code>request.app.state</code>.</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<code>False</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="doc-section-item">
|
||||
<td><code>package</code></td>
|
||||
<td>
|
||||
<code>bool</code>
|
||||
</td>
|
||||
<td>
|
||||
<div class="doc-md-description">
|
||||
<p>If <code>True</code>, emit <code><resource>/routes.py</code> packages (each with an
|
||||
<code>__init__.py</code>) instead of flat <code><resource>.py</code> modules.</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<code>False</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -641,19 +641,39 @@ must define an <code>operationId</code>, which becomes the handler function name
|
||||
<details class="notes" open>
|
||||
<summary>Notes</summary>
|
||||
<p><strong>Design constraints:</strong></p>
|
||||
<div class="language-text highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">1</span>
|
||||
<span class="normal">2</span>
|
||||
<span class="normal">3</span>
|
||||
<span class="normal">4</span>
|
||||
<span class="normal">5</span>
|
||||
<span class="normal">6</span>
|
||||
<span class="normal">7</span></pre></div></td><td class="code"><div><pre><span></span><code>- ``operationId`` is required on every operation (matching
|
||||
<div class="language-text highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"> 1</span>
|
||||
<span class="normal"> 2</span>
|
||||
<span class="normal"> 3</span>
|
||||
<span class="normal"> 4</span>
|
||||
<span class="normal"> 5</span>
|
||||
<span class="normal"> 6</span>
|
||||
<span class="normal"> 7</span>
|
||||
<span class="normal"> 8</span>
|
||||
<span class="normal"> 9</span>
|
||||
<span class="normal">10</span>
|
||||
<span class="normal">11</span>
|
||||
<span class="normal">12</span>
|
||||
<span class="normal">13</span>
|
||||
<span class="normal">14</span>
|
||||
<span class="normal">15</span>
|
||||
<span class="normal">16</span>
|
||||
<span class="normal">17</span></pre></div></td><td class="code"><div><pre><span></span><code>- ``operationId`` is required on every operation (matching
|
||||
``binder.bind_routes``).
|
||||
- Handlers are stubs raising ``NotImplementedError``.
|
||||
- Sub-resources (e.g. ``/pets/{id}/photo``) are grouped with their
|
||||
parent resource (``pets``).
|
||||
- Parameter types and defaults are inferred from the spec.
|
||||
- ``response: Response`` is injected for non-200 success codes.
|
||||
- Resource names are sanitized to valid Python module identifiers,
|
||||
so a path such as ``/fetch-requests`` yields ``fetch_requests.py``.
|
||||
- Passing ``inject_request=True`` prepends ``request: Request`` to
|
||||
every handler (the composition-root / DI convention).
|
||||
- ``multipart/form-data`` and
|
||||
``application/x-www-form-urlencoded`` request bodies expand to one
|
||||
parameter per schema property (``UploadFile`` / ``File`` / ``Form``)
|
||||
instead of an opaque ``payload: dict``.
|
||||
- Passing ``package=True`` writes ``<resource>/routes.py`` (with
|
||||
``__init__.py`` sidecars) instead of a flat ``<resource>.py``.
|
||||
</code></pre></div></td></tr></table></div>
|
||||
</details>
|
||||
|
||||
@@ -682,21 +702,25 @@ must define an <code>operationId</code>, which becomes the handler function name
|
||||
<span class="normal"><a href="#__codelineno-0-4">4</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-5">5</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-6">6</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-7">7</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="nf">generate_routes</span><span class="p">(</span>
|
||||
<span class="normal"><a href="#__codelineno-0-7">7</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-8">8</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-9">9</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="nf">generate_routes</span><span class="p">(</span>
|
||||
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2"></a> <span class="n">spec_path</span><span class="p">:</span> <span class="n">Path</span><span class="p">,</span>
|
||||
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3"></a> <span class="n">output_dir</span><span class="p">:</span> <span class="n">Path</span><span class="p">,</span>
|
||||
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4"></a> <span class="o">*</span><span class="p">,</span>
|
||||
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5"></a> <span class="n">use_models</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
|
||||
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6"></a> <span class="n">models_module</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">"models"</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="p">)</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="n">Path</span><span class="p">]</span>
|
||||
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6"></a> <span class="n">models_module</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">"models"</span><span class="p">,</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7"></a> <span class="n">inject_request</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
|
||||
</span><span id="__span-0-8"><a id="__codelineno-0-8" name="__codelineno-0-8"></a> <span class="n">package</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
|
||||
</span><span id="__span-0-9"><a id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="p">)</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="n">Path</span><span class="p">]</span>
|
||||
</span></code></pre></div></td></tr></table></div>
|
||||
|
||||
<div class="doc doc-contents ">
|
||||
|
||||
<p>Generate route handler stubs from an OpenAPI specification.</p>
|
||||
<p>Creates one <code><resource>.py</code> file per resource in <em>output_dir</em>.
|
||||
Resources are derived from the first path segment (e.g. <code>/pets</code>
|
||||
and <code>/pets/{id}</code> both group under <code>pets</code>).</p>
|
||||
<p>Creates one route module per resource in <em>output_dir</em>. Resources are
|
||||
derived from the first path segment (e.g. <code>/pets</code> and <code>/pets/{id}</code>
|
||||
both group under <code>pets</code>) and sanitized to valid module identifiers.</p>
|
||||
|
||||
|
||||
<p><span class="doc-section-title">Parameters:</span></p>
|
||||
@@ -769,6 +793,36 @@ for request-body schemas referenced via <code>$ref</code>.</p>
|
||||
<code>'models'</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="doc-section-item">
|
||||
<td><code>inject_request</code></td>
|
||||
<td>
|
||||
<code>bool</code>
|
||||
</td>
|
||||
<td>
|
||||
<div class="doc-md-description">
|
||||
<p>If <code>True</code>, prepend <code>request: Request</code> to every handler so the
|
||||
stub can later resolve services from <code>request.app.state</code>.</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<code>False</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="doc-section-item">
|
||||
<td><code>package</code></td>
|
||||
<td>
|
||||
<code>bool</code>
|
||||
</td>
|
||||
<td>
|
||||
<div class="doc-md-description">
|
||||
<p>If <code>True</code>, emit <code><resource>/routes.py</code> packages (each with an
|
||||
<code>__init__.py</code>) instead of flat <code><resource>.py</code> modules.</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<code>False</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -795,10 +795,10 @@ handlers explicitly via <code>operationId</code>.</p>
|
||||
</span><span id="__span-2-2"><a id="__codelineno-2-2" name="__codelineno-2-2"></a><span class="kn">import</span><span class="w"> </span><span class="nn">my_service.routes</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">routes</span>
|
||||
</span><span id="__span-2-3"><a id="__codelineno-2-3" name="__codelineno-2-3"></a>
|
||||
</span><span id="__span-2-4"><a id="__codelineno-2-4" name="__codelineno-2-4"></a><span class="n">api</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="n">OpenAPIFirstApp</span><span class="p">(</span>
|
||||
</span><span id="__span-2-5"><a id="__codelineno-2-5" name="__codelineno-2-5"></a> <span class="n">openapi_path</span><span class="o">=</span><span class="s2">"openapi.yaml"</span><span class="p">,</span>
|
||||
</span><span id="__span-2-5"><a id="__codelineno-2-5" name="__codelineno-2-5"></a> <span class="n">openapi_path</span><span class="o">=</span><span class="s2">"openapi.yaml"</span><span class="p">,</span>
|
||||
</span><span id="__span-2-6"><a id="__codelineno-2-6" name="__codelineno-2-6"></a> <span class="n">routes_module</span><span class="o">=</span><span class="n">routes</span><span class="p">,</span>
|
||||
</span><span id="__span-2-7"><a id="__codelineno-2-7" name="__codelineno-2-7"></a> <span class="n">title</span><span class="o">=</span><span class="s2">"My Service"</span><span class="p">,</span>
|
||||
</span><span id="__span-2-8"><a id="__codelineno-2-8" name="__codelineno-2-8"></a> <span class="n">version</span><span class="o">=</span><span class="s2">"1.0.0"</span><span class="p">,</span>
|
||||
</span><span id="__span-2-7"><a id="__codelineno-2-7" name="__codelineno-2-7"></a> <span class="n">title</span><span class="o">=</span><span class="s2">"My Service"</span><span class="p">,</span>
|
||||
</span><span id="__span-2-8"><a id="__codelineno-2-8" name="__codelineno-2-8"></a> <span class="n">version</span><span class="o">=</span><span class="s2">"1.0.0"</span><span class="p">,</span>
|
||||
</span><span id="__span-2-9"><a id="__codelineno-2-9" name="__codelineno-2-9"></a><span class="p">)</span>
|
||||
</span></code></pre></div></td></tr></table></div>
|
||||
<p>OperationId-driven HTTP client:</p>
|
||||
@@ -811,7 +811,7 @@ handlers explicitly via <code>operationId</code>.</p>
|
||||
<span class="normal"><a href="#__codelineno-3-7">7</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">openapi_first.loader</span><span class="w"> </span><span class="kn">import</span> <span class="n">load_openapi</span>
|
||||
</span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">openapi_first.client</span><span class="w"> </span><span class="kn">import</span> <span class="n">OpenAPIClient</span>
|
||||
</span><span id="__span-3-3"><a id="__codelineno-3-3" name="__codelineno-3-3"></a>
|
||||
</span><span id="__span-3-4"><a id="__codelineno-3-4" name="__codelineno-3-4"></a><span class="n">spec</span> <span class="o">=</span> <span class="n">load_openapi</span><span class="p">(</span><span class="s2">"openapi.yaml"</span><span class="p">)</span>
|
||||
</span><span id="__span-3-4"><a id="__codelineno-3-4" name="__codelineno-3-4"></a><span class="n">spec</span> <span class="o">=</span> <span class="n">load_openapi</span><span class="p">(</span><span class="s2">"openapi.yaml"</span><span class="p">)</span>
|
||||
</span><span id="__span-3-5"><a id="__codelineno-3-5" name="__codelineno-3-5"></a><span class="n">client</span> <span class="o">=</span> <span class="n">OpenAPIClient</span><span class="p">(</span><span class="n">spec</span><span class="p">)</span>
|
||||
</span><span id="__span-3-6"><a id="__codelineno-3-6" name="__codelineno-3-6"></a>
|
||||
</span><span id="__span-3-7"><a id="__codelineno-3-7" name="__codelineno-3-7"></a><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_health</span><span class="p">()</span>
|
||||
@@ -866,7 +866,9 @@ handlers explicitly via <code>operationId</code>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div><ul>
|
||||
<li><a href="openapi_first/">Openapi First</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -658,7 +658,7 @@ that enforces OpenAPI as the single source of truth for a FastAPI service.</p>
|
||||
Python handler function.
|
||||
- Handlers are plain Python callables (no FastAPI decorators).
|
||||
- FastAPI route registration is derived exclusively from the spec.
|
||||
- FastAPI's autogenerated OpenAPI schema is fully overridden.
|
||||
- FastAPI's autogenerated OpenAPI schema is fully overridden.
|
||||
</code></pre></div></td></tr></table></div>
|
||||
<p><strong>Responsibilities:</strong></p>
|
||||
<div class="language-text highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">1</span>
|
||||
@@ -821,7 +821,7 @@ handlers).</p>
|
||||
- All routes are derived from the provided OpenAPI specification,
|
||||
and each ``operationId`` is mapped to a Python function in the
|
||||
supplied routes module.
|
||||
- Auth dependencies are auto-injected from the spec's
|
||||
- Auth dependencies are auto-injected from the spec's
|
||||
``securitySchemes`` and per-operation ``security`` fields.
|
||||
</code></pre></div></td></tr></table></div>
|
||||
<p><strong>Guarantees:</strong></p>
|
||||
@@ -852,9 +852,9 @@ handlers).</p>
|
||||
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2"></a><span class="kn">import</span><span class="w"> </span><span class="nn">app.routes</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">routes</span>
|
||||
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3"></a>
|
||||
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4"></a><span class="n">app</span> <span class="o">=</span> <span class="n">OpenAPIFirstApp</span><span class="p">(</span>
|
||||
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5"></a> <span class="n">openapi_path</span><span class="o">=</span><span class="s2">"app/openapi.json"</span><span class="p">,</span>
|
||||
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5"></a> <span class="n">openapi_path</span><span class="o">=</span><span class="s2">"app/openapi.json"</span><span class="p">,</span>
|
||||
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6"></a> <span class="n">routes_module</span><span class="o">=</span><span class="n">routes</span><span class="p">,</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7"></a> <span class="n">title</span><span class="o">=</span><span class="s2">"Example Service"</span><span class="p">,</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7"></a> <span class="n">title</span><span class="o">=</span><span class="s2">"Example Service"</span><span class="p">,</span>
|
||||
</span><span id="__span-0-8"><a id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="p">)</span>
|
||||
</span></code></pre></div></td></tr></table></div>
|
||||
</details>
|
||||
|
||||
@@ -836,16 +836,16 @@ missing/duplicate, or required parameters are missing.</p>
|
||||
<span class="normal"><a href="#__codelineno-0-15">15</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-16">16</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">openapi_first</span><span class="w"> </span><span class="kn">import</span> <span class="n">loader</span><span class="p">,</span> <span class="n">client</span>
|
||||
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2"></a>
|
||||
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="n">spec</span> <span class="o">=</span> <span class="n">loader</span><span class="o">.</span><span class="n">load_openapi</span><span class="p">(</span><span class="s2">"openapi.yaml"</span><span class="p">)</span>
|
||||
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3"></a><span class="n">spec</span> <span class="o">=</span> <span class="n">loader</span><span class="o">.</span><span class="n">load_openapi</span><span class="p">(</span><span class="s2">"openapi.yaml"</span><span class="p">)</span>
|
||||
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4"></a>
|
||||
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5"></a><span class="n">api</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">OpenAPIClient</span><span class="p">(</span>
|
||||
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6"></a> <span class="n">spec</span><span class="o">=</span><span class="n">spec</span><span class="p">,</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7"></a> <span class="n">base_url</span><span class="o">=</span><span class="s2">"http://localhost:8000"</span><span class="p">,</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7"></a> <span class="n">base_url</span><span class="o">=</span><span class="s2">"http://localhost:8000"</span><span class="p">,</span>
|
||||
</span><span id="__span-0-8"><a id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="p">)</span>
|
||||
</span><span id="__span-0-9"><a id="__codelineno-0-9" name="__codelineno-0-9"></a>
|
||||
</span><span id="__span-0-10"><a id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="c1"># Call operationId: getUser</span>
|
||||
</span><span id="__span-0-11"><a id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="n">response</span> <span class="o">=</span> <span class="n">api</span><span class="o">.</span><span class="n">getUser</span><span class="p">(</span>
|
||||
</span><span id="__span-0-12"><a id="__codelineno-0-12" name="__codelineno-0-12"></a> <span class="n">path_params</span><span class="o">=</span><span class="p">{</span><span class="s2">"user_id"</span><span class="p">:</span> <span class="mi">123</span><span class="p">}</span>
|
||||
</span><span id="__span-0-12"><a id="__codelineno-0-12" name="__codelineno-0-12"></a> <span class="n">path_params</span><span class="o">=</span><span class="p">{</span><span class="s2">"user_id"</span><span class="p">:</span> <span class="mi">123</span><span class="p">}</span>
|
||||
</span><span id="__span-0-13"><a id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="p">)</span>
|
||||
</span><span id="__span-0-14"><a id="__codelineno-0-14" name="__codelineno-0-14"></a>
|
||||
</span><span id="__span-0-15"><a id="__codelineno-0-15" name="__codelineno-0-15"></a><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">status_code</span><span class="p">)</span>
|
||||
|
||||
@@ -762,21 +762,25 @@ definitions.</p>
|
||||
<span class="normal"><a href="#__codelineno-0-4">4</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-5">5</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-6">6</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-7">7</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="nf">generate_routes</span><span class="p">(</span>
|
||||
<span class="normal"><a href="#__codelineno-0-7">7</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-8">8</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-9">9</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="nf">generate_routes</span><span class="p">(</span>
|
||||
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2"></a> <span class="n">spec_path</span><span class="p">:</span> <span class="n">Path</span><span class="p">,</span>
|
||||
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3"></a> <span class="n">output_dir</span><span class="p">:</span> <span class="n">Path</span><span class="p">,</span>
|
||||
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4"></a> <span class="o">*</span><span class="p">,</span>
|
||||
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5"></a> <span class="n">use_models</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
|
||||
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6"></a> <span class="n">models_module</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">"models"</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="p">)</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="n">Path</span><span class="p">]</span>
|
||||
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6"></a> <span class="n">models_module</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">"models"</span><span class="p">,</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7"></a> <span class="n">inject_request</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
|
||||
</span><span id="__span-0-8"><a id="__codelineno-0-8" name="__codelineno-0-8"></a> <span class="n">package</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
|
||||
</span><span id="__span-0-9"><a id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="p">)</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="n">Path</span><span class="p">]</span>
|
||||
</span></code></pre></div></td></tr></table></div>
|
||||
|
||||
<div class="doc doc-contents ">
|
||||
|
||||
<p>Generate route handler stubs from an OpenAPI specification.</p>
|
||||
<p>Creates one <code><resource>.py</code> file per resource in <em>output_dir</em>.
|
||||
Resources are derived from the first path segment (e.g. <code>/pets</code>
|
||||
and <code>/pets/{id}</code> both group under <code>pets</code>).</p>
|
||||
<p>Creates one route module per resource in <em>output_dir</em>. Resources are
|
||||
derived from the first path segment (e.g. <code>/pets</code> and <code>/pets/{id}</code>
|
||||
both group under <code>pets</code>) and sanitized to valid module identifiers.</p>
|
||||
|
||||
|
||||
<p><span class="doc-section-title">Parameters:</span></p>
|
||||
@@ -849,6 +853,36 @@ for request-body schemas referenced via <code>$ref</code>.</p>
|
||||
<code>'models'</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="doc-section-item">
|
||||
<td><code>inject_request</code></td>
|
||||
<td>
|
||||
<code>bool</code>
|
||||
</td>
|
||||
<td>
|
||||
<div class="doc-md-description">
|
||||
<p>If <code>True</code>, prepend <code>request: Request</code> to every handler so the
|
||||
stub can later resolve services from <code>request.app.state</code>.</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<code>False</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="doc-section-item">
|
||||
<td><code>package</code></td>
|
||||
<td>
|
||||
<code>bool</code>
|
||||
</td>
|
||||
<td>
|
||||
<div class="doc-md-description">
|
||||
<p>If <code>True</code>, emit <code><resource>/routes.py</code> packages (each with an
|
||||
<code>__init__.py</code>) instead of flat <code><resource>.py</code> modules.</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<code>False</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -641,19 +641,39 @@ must define an <code>operationId</code>, which becomes the handler function name
|
||||
<details class="notes" open>
|
||||
<summary>Notes</summary>
|
||||
<p><strong>Design constraints:</strong></p>
|
||||
<div class="language-text highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal">1</span>
|
||||
<span class="normal">2</span>
|
||||
<span class="normal">3</span>
|
||||
<span class="normal">4</span>
|
||||
<span class="normal">5</span>
|
||||
<span class="normal">6</span>
|
||||
<span class="normal">7</span></pre></div></td><td class="code"><div><pre><span></span><code>- ``operationId`` is required on every operation (matching
|
||||
<div class="language-text highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"> 1</span>
|
||||
<span class="normal"> 2</span>
|
||||
<span class="normal"> 3</span>
|
||||
<span class="normal"> 4</span>
|
||||
<span class="normal"> 5</span>
|
||||
<span class="normal"> 6</span>
|
||||
<span class="normal"> 7</span>
|
||||
<span class="normal"> 8</span>
|
||||
<span class="normal"> 9</span>
|
||||
<span class="normal">10</span>
|
||||
<span class="normal">11</span>
|
||||
<span class="normal">12</span>
|
||||
<span class="normal">13</span>
|
||||
<span class="normal">14</span>
|
||||
<span class="normal">15</span>
|
||||
<span class="normal">16</span>
|
||||
<span class="normal">17</span></pre></div></td><td class="code"><div><pre><span></span><code>- ``operationId`` is required on every operation (matching
|
||||
``binder.bind_routes``).
|
||||
- Handlers are stubs raising ``NotImplementedError``.
|
||||
- Sub-resources (e.g. ``/pets/{id}/photo``) are grouped with their
|
||||
parent resource (``pets``).
|
||||
- Parameter types and defaults are inferred from the spec.
|
||||
- ``response: Response`` is injected for non-200 success codes.
|
||||
- Resource names are sanitized to valid Python module identifiers,
|
||||
so a path such as ``/fetch-requests`` yields ``fetch_requests.py``.
|
||||
- Passing ``inject_request=True`` prepends ``request: Request`` to
|
||||
every handler (the composition-root / DI convention).
|
||||
- ``multipart/form-data`` and
|
||||
``application/x-www-form-urlencoded`` request bodies expand to one
|
||||
parameter per schema property (``UploadFile`` / ``File`` / ``Form``)
|
||||
instead of an opaque ``payload: dict``.
|
||||
- Passing ``package=True`` writes ``<resource>/routes.py`` (with
|
||||
``__init__.py`` sidecars) instead of a flat ``<resource>.py``.
|
||||
</code></pre></div></td></tr></table></div>
|
||||
</details>
|
||||
|
||||
@@ -682,21 +702,25 @@ must define an <code>operationId</code>, which becomes the handler function name
|
||||
<span class="normal"><a href="#__codelineno-0-4">4</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-5">5</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-6">6</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-7">7</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="nf">generate_routes</span><span class="p">(</span>
|
||||
<span class="normal"><a href="#__codelineno-0-7">7</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-8">8</a></span>
|
||||
<span class="normal"><a href="#__codelineno-0-9">9</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1"></a><span class="nf">generate_routes</span><span class="p">(</span>
|
||||
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2"></a> <span class="n">spec_path</span><span class="p">:</span> <span class="n">Path</span><span class="p">,</span>
|
||||
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3"></a> <span class="n">output_dir</span><span class="p">:</span> <span class="n">Path</span><span class="p">,</span>
|
||||
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4"></a> <span class="o">*</span><span class="p">,</span>
|
||||
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5"></a> <span class="n">use_models</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
|
||||
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6"></a> <span class="n">models_module</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">"models"</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="p">)</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="n">Path</span><span class="p">]</span>
|
||||
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6"></a> <span class="n">models_module</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">"models"</span><span class="p">,</span>
|
||||
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7"></a> <span class="n">inject_request</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
|
||||
</span><span id="__span-0-8"><a id="__codelineno-0-8" name="__codelineno-0-8"></a> <span class="n">package</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
|
||||
</span><span id="__span-0-9"><a id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="p">)</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="n">Path</span><span class="p">]</span>
|
||||
</span></code></pre></div></td></tr></table></div>
|
||||
|
||||
<div class="doc doc-contents ">
|
||||
|
||||
<p>Generate route handler stubs from an OpenAPI specification.</p>
|
||||
<p>Creates one <code><resource>.py</code> file per resource in <em>output_dir</em>.
|
||||
Resources are derived from the first path segment (e.g. <code>/pets</code>
|
||||
and <code>/pets/{id}</code> both group under <code>pets</code>).</p>
|
||||
<p>Creates one route module per resource in <em>output_dir</em>. Resources are
|
||||
derived from the first path segment (e.g. <code>/pets</code> and <code>/pets/{id}</code>
|
||||
both group under <code>pets</code>) and sanitized to valid module identifiers.</p>
|
||||
|
||||
|
||||
<p><span class="doc-section-title">Parameters:</span></p>
|
||||
@@ -769,6 +793,36 @@ for request-body schemas referenced via <code>$ref</code>.</p>
|
||||
<code>'models'</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="doc-section-item">
|
||||
<td><code>inject_request</code></td>
|
||||
<td>
|
||||
<code>bool</code>
|
||||
</td>
|
||||
<td>
|
||||
<div class="doc-md-description">
|
||||
<p>If <code>True</code>, prepend <code>request: Request</code> to every handler so the
|
||||
stub can later resolve services from <code>request.app.state</code>.</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<code>False</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="doc-section-item">
|
||||
<td><code>package</code></td>
|
||||
<td>
|
||||
<code>bool</code>
|
||||
</td>
|
||||
<td>
|
||||
<div class="doc-md-description">
|
||||
<p>If <code>True</code>, emit <code><resource>/routes.py</code> packages (each with an
|
||||
<code>__init__.py</code>) instead of flat <code><resource>.py</code> modules.</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<code>False</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -682,10 +682,10 @@ handlers explicitly via <code>operationId</code>.</p>
|
||||
</span><span id="__span-2-2"><a id="__codelineno-2-2" name="__codelineno-2-2"></a><span class="kn">import</span><span class="w"> </span><span class="nn">my_service.routes</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">routes</span>
|
||||
</span><span id="__span-2-3"><a id="__codelineno-2-3" name="__codelineno-2-3"></a>
|
||||
</span><span id="__span-2-4"><a id="__codelineno-2-4" name="__codelineno-2-4"></a><span class="n">api</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="n">OpenAPIFirstApp</span><span class="p">(</span>
|
||||
</span><span id="__span-2-5"><a id="__codelineno-2-5" name="__codelineno-2-5"></a> <span class="n">openapi_path</span><span class="o">=</span><span class="s2">"openapi.yaml"</span><span class="p">,</span>
|
||||
</span><span id="__span-2-5"><a id="__codelineno-2-5" name="__codelineno-2-5"></a> <span class="n">openapi_path</span><span class="o">=</span><span class="s2">"openapi.yaml"</span><span class="p">,</span>
|
||||
</span><span id="__span-2-6"><a id="__codelineno-2-6" name="__codelineno-2-6"></a> <span class="n">routes_module</span><span class="o">=</span><span class="n">routes</span><span class="p">,</span>
|
||||
</span><span id="__span-2-7"><a id="__codelineno-2-7" name="__codelineno-2-7"></a> <span class="n">title</span><span class="o">=</span><span class="s2">"My Service"</span><span class="p">,</span>
|
||||
</span><span id="__span-2-8"><a id="__codelineno-2-8" name="__codelineno-2-8"></a> <span class="n">version</span><span class="o">=</span><span class="s2">"1.0.0"</span><span class="p">,</span>
|
||||
</span><span id="__span-2-7"><a id="__codelineno-2-7" name="__codelineno-2-7"></a> <span class="n">title</span><span class="o">=</span><span class="s2">"My Service"</span><span class="p">,</span>
|
||||
</span><span id="__span-2-8"><a id="__codelineno-2-8" name="__codelineno-2-8"></a> <span class="n">version</span><span class="o">=</span><span class="s2">"1.0.0"</span><span class="p">,</span>
|
||||
</span><span id="__span-2-9"><a id="__codelineno-2-9" name="__codelineno-2-9"></a><span class="p">)</span>
|
||||
</span></code></pre></div></td></tr></table></div>
|
||||
<p>OperationId-driven HTTP client:</p>
|
||||
@@ -698,7 +698,7 @@ handlers explicitly via <code>operationId</code>.</p>
|
||||
<span class="normal"><a href="#__codelineno-3-7">7</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">openapi_first.loader</span><span class="w"> </span><span class="kn">import</span> <span class="n">load_openapi</span>
|
||||
</span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">openapi_first.client</span><span class="w"> </span><span class="kn">import</span> <span class="n">OpenAPIClient</span>
|
||||
</span><span id="__span-3-3"><a id="__codelineno-3-3" name="__codelineno-3-3"></a>
|
||||
</span><span id="__span-3-4"><a id="__codelineno-3-4" name="__codelineno-3-4"></a><span class="n">spec</span> <span class="o">=</span> <span class="n">load_openapi</span><span class="p">(</span><span class="s2">"openapi.yaml"</span><span class="p">)</span>
|
||||
</span><span id="__span-3-4"><a id="__codelineno-3-4" name="__codelineno-3-4"></a><span class="n">spec</span> <span class="o">=</span> <span class="n">load_openapi</span><span class="p">(</span><span class="s2">"openapi.yaml"</span><span class="p">)</span>
|
||||
</span><span id="__span-3-5"><a id="__codelineno-3-5" name="__codelineno-3-5"></a><span class="n">client</span> <span class="o">=</span> <span class="n">OpenAPIClient</span><span class="p">(</span><span class="n">spec</span><span class="p">)</span>
|
||||
</span><span id="__span-3-6"><a id="__codelineno-3-6" name="__codelineno-3-6"></a>
|
||||
</span><span id="__span-3-7"><a id="__codelineno-3-7" name="__codelineno-3-7"></a><span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">get_health</span><span class="p">()</span>
|
||||
|
||||
@@ -688,7 +688,7 @@ construct a strict, operationId-driven HTTP client.</p>
|
||||
<span class="normal">29</span></pre></div></td><td class="code"><div><pre><span></span><code>from openapi_first.loader import load_openapi
|
||||
from openapi_first.client import OpenAPIClient
|
||||
|
||||
spec = load_openapi("openapi.yaml")
|
||||
spec = load_openapi("openapi.yaml")
|
||||
client = OpenAPIClient(spec)
|
||||
|
||||
# List items
|
||||
@@ -696,23 +696,23 @@ response = client.list_items()
|
||||
|
||||
# Get item by ID
|
||||
response = client.get_item(
|
||||
path_params={"item_id": 1}
|
||||
path_params={"item_id": 1}
|
||||
)
|
||||
|
||||
# Create item
|
||||
response = client.create_item(
|
||||
body={"name": "Orange", "price": 0.8}
|
||||
body={"name": "Orange", "price": 0.8}
|
||||
)
|
||||
|
||||
# Update item
|
||||
response = client.update_item(
|
||||
path_params={"item_id": 1},
|
||||
body={"name": "Green Apple", "price": 0.6},
|
||||
path_params={"item_id": 1},
|
||||
body={"name": "Green Apple", "price": 0.6},
|
||||
)
|
||||
|
||||
# Delete item
|
||||
response = client.delete_item(
|
||||
path_params={"item_id": 1}
|
||||
path_params={"item_id": 1}
|
||||
)
|
||||
</code></pre></div></td></tr></table></div>
|
||||
<p>Client guarantees:
|
||||
|
||||
@@ -659,13 +659,13 @@ construct a strict, operationId-driven HTTP client.</p>
|
||||
<span class="normal">10</span></pre></div></td><td class="code"><div><pre><span></span><code>from openapi_first.loader import load_openapi
|
||||
from openapi_first.client import OpenAPIClient
|
||||
|
||||
spec = load_openapi("openapi.yaml")
|
||||
spec = load_openapi("openapi.yaml")
|
||||
client = OpenAPIClient(spec)
|
||||
|
||||
response = client.get_health()
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"status": "ok"}
|
||||
assert response.json() == {"status": "ok"}
|
||||
</code></pre></div></td></tr></table></div>
|
||||
<p>Client guarantees:
|
||||
- One callable per OpenAPI <code>operationId</code>
|
||||
|
||||
@@ -691,7 +691,7 @@ construct a strict, operationId-driven HTTP client.</p>
|
||||
<span class="normal">29</span></pre></div></td><td class="code"><div><pre><span></span><code>from openapi_first.loader import load_openapi
|
||||
from openapi_first.client import OpenAPIClient
|
||||
|
||||
spec = load_openapi("openapi.yaml")
|
||||
spec = load_openapi("openapi.yaml")
|
||||
client = OpenAPIClient(spec)
|
||||
|
||||
# List items
|
||||
@@ -699,23 +699,23 @@ response = client.list_items()
|
||||
|
||||
# Get item by ID
|
||||
response = client.get_item(
|
||||
path_params={"item_id": 1}
|
||||
path_params={"item_id": 1}
|
||||
)
|
||||
|
||||
# Create item
|
||||
response = client.create_item(
|
||||
body={"name": "Orange", "price": 0.8}
|
||||
body={"name": "Orange", "price": 0.8}
|
||||
)
|
||||
|
||||
# Update item
|
||||
response = client.update_item(
|
||||
path_params={"item_id": 1},
|
||||
body={"name": "Green Apple", "price": 0.6},
|
||||
path_params={"item_id": 1},
|
||||
body={"name": "Green Apple", "price": 0.6},
|
||||
)
|
||||
|
||||
# Delete item
|
||||
response = client.delete_item(
|
||||
path_params={"item_id": 1}
|
||||
path_params={"item_id": 1}
|
||||
)
|
||||
</code></pre></div></td></tr></table></div>
|
||||
<p>Client guarantees:
|
||||
|
||||
@@ -699,21 +699,21 @@ library API surface.</p>
|
||||
<span class="normal">19</span></pre></div></td><td class="code"><div><pre><span></span><code>from openapi_first.loader import load_openapi
|
||||
from openapi_first.client import OpenAPIClient
|
||||
|
||||
spec = load_openapi("openapi.yaml")
|
||||
spec = load_openapi("openapi.yaml")
|
||||
client = OpenAPIClient(spec)
|
||||
|
||||
# List pets with pagination
|
||||
response = client.list_pets(query_params={"limit": 10, "offset": 0})
|
||||
response = client.list_pets(query_params={"limit": 10, "offset": 0})
|
||||
|
||||
# Create a pet with FK references
|
||||
response = client.create_pet(
|
||||
body={"name": "Fido", "species": "dog", "parents": [1, 2]}
|
||||
body={"name": "Fido", "species": "dog", "parents": [1, 2]}
|
||||
)
|
||||
|
||||
# Upload a pet photo
|
||||
response = client.upload_pet_photo(
|
||||
path_params={"id": 1},
|
||||
body={"file": open("photo.jpg", "rb")},
|
||||
path_params={"id": 1},
|
||||
body={"file": open("photo.jpg", "rb")},
|
||||
)
|
||||
</code></pre></div></td></tr></table></div>
|
||||
<hr />
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Reference in New Issue
Block a user