<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>API Design · 仁才徳</title>
    <link>https://jared.lynskey.co.nz/ja/tags/api-design/</link>
    <description>ソフトウェアエンジニアリングと開発組織のリーダーシップについて。評価、採用とチームの拡大、CI/CD、DevOps モニタリング、エージェンティック AI。ソウルより。</description>
    <generator>Hugo</generator>
    <language>ja</language>
    <copyright>© 2026 仁才徳</copyright>
    <lastBuildDate>Wed, 28 Oct 2026 00:00:00 +1300</lastBuildDate>
    <atom:link href="https://jared.lynskey.co.nz/ja/tags/api-design/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>APIデザインファーストの進め方：スプリントごとにOpenAPIのコントラクトを決める</title>
      <link>https://jared.lynskey.co.nz/ja/posts/2023/2023-10-08-planning-an-api/</link>
      <guid isPermaLink="true">https://jared.lynskey.co.nz/ja/posts/2023/2023-10-08-planning-an-api/</guid>
      <pubDate>Mon, 09 Oct 2023 00:30:03 +0000</pubDate>
      <dc:creator>Jared Lynskey</dc:creator>
      <category>API</category>
      <category>OpenAPI</category>
      <category>API Design</category>
      <category>Planning</category>
      <category>Mock Server</category>
      <description>スプリントごとに回すAPIデザインファースト（スキーマ駆動開発）の進め方です。バックエンドとフロントの担当がOpenAPIのコントラクトに合意し、CIがモックサーバーを立て、両者が並行して開発します。YAMLの例付き。</description>
      <content:encoded><![CDATA[<p>先日、<a href="https://jared.lynskey.co.nz/ja/posts/2023/2023-10-08-open-api/" >OpenAPIによるAPIファースト開発</a>について一般論を書きました。今回はその具体版です。うちのチームで試している計画ワークフローと、それに添えるYAMLの例を紹介します。</p>
<p>先に要点をまとめると、このデザインファーストのプロセスはスプリントごとに次の流れで回します。</p>
<ol>
<li>そのスプリントのAPI作業の担当を、バックエンドとフロントエンドから1人ずつ決める。</li>
<li>2人でスプリントの要件に沿ってOpenAPIスキーマを書く（または更新する）。双方が納得するまでレビューする。</li>
<li>スキーマをリポジトリにコミットする。ここから先は、これがコントラクトになる。</li>
<li>コミットされたスキーマから、CIがモックサーバーを立てる。</li>
<li>フロントエンドはモックに対して開発し、その間にバックエンドが本物のエンドポイントを実装する。</li>
<li>本物のサービスがデプロイされたら、そこから生成されたスペックを次のスプリントのスキーマの出発点にする。</li>
</ol>

<h2 class="relative group">きっかけ
    <div id="きっかけ" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e3%81%8d%e3%81%a3%e3%81%8b%e3%81%91" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>発端はレトロスペクティブでした。APIの計画がいかに見えていないか、フィードバックは容赦なかった。バックエンドは要件を自分たちなりに解釈してエンドポイントを作り、フロントエンドは後からレスポンスの形を知り、ズレは統合の段階、つまり一番高くつくタイミングで発覚する。そこで出た提案が、両サイドを計画段階から巻き込み、OpenAPIスキーマをすべての土台にしようというものでした。</p>

<h2 class="relative group">プロセス
    <div id="プロセス" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e3%83%97%e3%83%ad%e3%82%bb%e3%82%b9" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>毎週、バックエンドとフロントエンドから1人ずつ、計2人の代表を選びます。代表の仕事は、スプリントの要件を理解して、計画用のOpenAPIスキーマをそれに合わせることです。2人でスキーマをレビューし、合っていない部分を直していけば、作り始める前に、双方が何を作るのかを正確に把握できます。</p>
<p>修正が落ち着いたら、スキーマをリポジトリにコミットします。するとCI/CDがそのyamlからモックAPIを生成します。スプリントが終わったら、次のスプリントのAPI要件をまとめた新しいyamlを切って、同じサイクルを繰り返します。</p>

<h2 class="relative group">ツールまわりのメモ
    <div id="ツールまわりのメモ" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e3%83%84%e3%83%bc%e3%83%ab%e3%81%be%e3%82%8f%e3%82%8a%e3%81%ae%e3%83%a1%e3%83%a2" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>yamlの可視化には<a href="https://editor.swagger.io/"  target="_blank" rel="noreferrer">Swagger Editor</a>で十分です。ファイルをアップロードすれば、ちゃんとしたSwaggerドキュメントとして表示されます。</p>
<p>CI/CDパイプラインには、yamlを受け取ってモックサーバーを立てる仕組みが必要です。Stoplightの<a href="https://github.com/stoplightio/prism"  target="_blank" rel="noreferrer">Prism</a>は広く使われている選択肢で、OpenAPI 3.1にも対応しています。</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install -g @stoplight/prism-cli
</span></span><span class="line"><span class="cl">prism mock openapi.yaml</span></span></code></pre></div></div>
<p>これでスキーマ内のすべてのパスが <code>http://127.0.0.1:4010</code> で提供され、スキーマの <code>examples</code> がそのままレスポンスとして返ってきます。たとえば <code>GET /lists/10</code> なら、付録のサンプルのリストが返ります。コントラクトもきちんと守らせてくれます。例ではAPIキーを宣言しているので、<code>X-API-Key</code> ヘッダーのないリクエストには401が返ります。フロントエンドが作り込むべきなのは、まさにこの挙動です。コンテナの中で動かすときは、外からアクセスできるように <code>-h 0.0.0.0</code> を付けてください。<a href="https://github.com/muonsoft/openapi-mock"  target="_blank" rel="noreferrer">openapi-mock</a>は、ランダムなデータでレスポンスを埋めてくれる、より軽量な選択肢です。</p>
<p>モックを立てる前にスキーマをリントしておくのもおすすめです。壊れたコントラクトがあればビルドが失敗するので、フロントエンドが混乱せずに済みます。<a href="https://github.com/stoplightio/spectral"  target="_blank" rel="noreferrer">Spectral</a>は、1行のルールセットを置けば動きます。</p>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install -g @stoplight/spectral-cli
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;extends: [&#34;spectral:oas&#34;]&#39;</span> &gt; .spectral.yaml
</span></span><span class="line"><span class="cl">spectral lint openapi.yaml</span></span></code></pre></div></div>
<p>最後に、このスキーマはあくまで計画用の成果物です。本物のAPIがデプロイされたら、各サービスが自分のopenapi.jsonを生成するべきで、それをダウンロードして次の計画に再利用します。</p>

<h2 class="relative group">なぜやる価値があるのか
    <div id="なぜやる価値があるのか" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e3%81%aa%e3%81%9c%e3%82%84%e3%82%8b%e4%be%a1%e5%80%a4%e3%81%8c%e3%81%82%e3%82%8b%e3%81%ae%e3%81%8b" aria-label="アンカー">#</a>
    </span>
    
</h2>
<p>議論が一番安い場所に移動するからです。スキーマを書いている段階でフロントとバックのエンジニアが同席していれば、誤解はコードになる前に捕まります。API要件はスプリント途中で再交渉されるのではなく一度で合意されるし、モックサーバーのおかげでフロントエンドは待たずにすぐ着手できる。重要な細部の見落としもぐっと減ります。なにしろ2組の目と、書面になった契約をすり抜けなければならないので。</p>
<p>革命的な話はひとつもありません。ただ、機械がモックとして返せるくらい具体的なところまで計画を落とし込んだだけです。そして結局のところ、計画に必要な具体性とは、ちょうどそのくらいなのだと思います。</p>

<h2 class="relative group">付録A - yamlの例
    <div id="付録a---yamlの例" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%bb%98%e9%8c%b2a---yaml%e3%81%ae%e4%be%8b" aria-label="アンカー">#</a>
    </span>
    
</h2>
<div class="highlight-wrapper"><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">openapi</span><span class="p">:</span><span class="w"> </span><span class="m">3.1.0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">info</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">title</span><span class="p">:</span><span class="w"> </span><span class="l">MyApp Sprint 3</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">description</span><span class="p">:</span><span class="w"> </span><span class="l">Planning schema for sprint 3. Drives the mock server only.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="m">0.3.0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">servers</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">url</span><span class="p">:</span><span class="w"> </span><span class="l">https://api-mock.example.com/v1</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">tags</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">lists</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">description</span><span class="p">:</span><span class="w"> </span><span class="l">Saved lists feature (PROJ-123)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">security</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">api_key</span><span class="p">:</span><span class="w"> </span><span class="p">[]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">paths</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">/lists</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">get</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">tags</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">lists]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">summary</span><span class="p">:</span><span class="w"> </span><span class="l">Return the current user&#39;s saved lists</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">operationId</span><span class="p">:</span><span class="w"> </span><span class="l">getLists</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">responses</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">&#39;200&#39;</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">description</span><span class="p">:</span><span class="w"> </span><span class="l">OK</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">content</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">application/json</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span><span class="nt">schema</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">array</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">items</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                  </span><span class="nt">$ref</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;#/components/schemas/List&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="l">/lists/{listId}:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">get</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">tags</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">lists]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">summary</span><span class="p">:</span><span class="w"> </span><span class="l">Find a list by ID</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">operationId</span><span class="p">:</span><span class="w"> </span><span class="l">getListById</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">parameters</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">listId</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">in</span><span class="p">:</span><span class="w"> </span><span class="l">path</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">required</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">schema</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">integer</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">format</span><span class="p">:</span><span class="w"> </span><span class="l">int64</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">responses</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">&#39;200&#39;</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">description</span><span class="p">:</span><span class="w"> </span><span class="l">OK</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">content</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="nt">application/json</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">              </span><span class="nt">schema</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="nt">$ref</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;#/components/schemas/List&#39;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">&#39;404&#39;</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">description</span><span class="p">:</span><span class="w"> </span><span class="l">List not found</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">components</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">schemas</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">List</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">object</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">required</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">id, title]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">properties</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">id</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">integer</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">format</span><span class="p">:</span><span class="w"> </span><span class="l">int64</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">examples</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="m">10</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">title</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">string</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">examples</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">Weekend reading]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">itemCount</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">integer</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">          </span><span class="nt">examples</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="m">7</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">securitySchemes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">api_key</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l">apiKey</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">X-API-Key</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">in</span><span class="p">:</span><span class="w"> </span><span class="l">header</span></span></span></code></pre></div></div>
]]></content:encoded>
      <media:content url="https://jared.lynskey.co.nz/en/posts/2023/2023-10-08-planning-an-api/featured.jpeg" medium="image" type="image/jpeg" />
    </item>
    <item>
      <title>APIファースト開発をOpenAPIで：フロントエンドとバックエンドを並行して進める</title>
      <link>https://jared.lynskey.co.nz/ja/posts/2023/2023-10-08-open-api/</link>
      <guid isPermaLink="true">https://jared.lynskey.co.nz/ja/posts/2023/2023-10-08-open-api/</guid>
      <pubDate>Sun, 08 Oct 2023 00:30:03 +0000</pubDate>
      <dc:creator>Jared Lynskey</dc:creator>
      <category>OpenAPI</category>
      <category>backend</category>
      <category>frontend</category>
      <category>API design</category>
      <category>software development</category>
      <category>team collaboration</category>
      <description>APIファースト開発の実践編です。先にOpenAPIでコントラクトに合意し、モックサーバーを立てれば、フロントエンドはバックエンドを待たずに済みます。</description>
      <content:encoded><![CDATA[<p>これまで見てきた中で一番確実にスケジュールを殺すのは、難しいエンジニアリングではありません。「もうすぐできる」エンドポイントを、フロントエンドがひたすら待っている状態です。職場で落ち着いた解決策は地味ですが効きます。コードを書く前に、まずOpenAPIでAPIコントラクトに合意することです。</p>

<h3 class="relative group">待ちのゲーム
    <div id="待ちのゲーム" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%be%85%e3%81%a1%e3%81%ae%e3%82%b2%e3%83%bc%e3%83%a0" aria-label="アンカー">#</a>
    </span>
    
</h3>
<p>従来のフローは直列です。バックエンドがAPIを設計・実装し、エンドポイントが実際に動くようになってから、フロントエンドが統合を始める。バックエンドの遅れはすべてフロントエンドのカレンダーに直撃しますし、リリース日が載っているのはたいていフロントエンドのカレンダーです。</p>

<h3 class="relative group">コードより先にコントラクト
    <div id="コードより先にコントラクト" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e3%82%b3%e3%83%bc%e3%83%89%e3%82%88%e3%82%8a%e5%85%88%e3%81%ab%e3%82%b3%e3%83%b3%e3%83%88%e3%83%a9%e3%82%af%e3%83%88" aria-label="アンカー">#</a>
    </span>
    
</h3>
<p>スキーマファーストのフローでは、両者がほぼ同時に走り出せます。コードが1行も存在しない段階で、APIの構造をOpenAPIスキーマに書き出します。すべてのエンドポイント、リクエストとレスポンスのモデル、認証方式、エラーコード。このドキュメントが、フロントエンドとバックエンドの間の契約書になります。</p>
<p>見返りはすぐに現れます。作る前に、全員が同じ形で機能を理解できる。バックエンドが実装中でも、フロントエンドはUIを作り始められる。合意済みの唯一の情報源を更新すればいいので、変更も速く回る。さらにスキーマから直接モックサーバーを生成できるので、本物のエンドポイントがひとつもない段階からフロントエンドのテストが始められます。</p>

<h3 class="relative group">実際の回し方
    <div id="実際の回し方" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%ae%9f%e9%9a%9b%e3%81%ae%e5%9b%9e%e3%81%97%e6%96%b9" aria-label="アンカー">#</a>
    </span>
    
</h3>
<ol>
<li>要件を集める。これは何を作るときでも同じです。</li>
<li>スキーマを設計する。エンドポイント、リクエスト／レスポンスモデル、認証、エラーコード。</li>
<li>フロントとバックの両方でレビューする。コントラクトが本領を発揮するのはここです。</li>
<li>モックサーバーを生成し（SwaggerでもPostmanでも可能です）、フロントエンドはそれに対して統合を進める。</li>
<li>バックエンドは同じスキーマに沿って本物のエンドポイントを実装する。</li>
<li>出来上がったものからモックを本物に差し替え、契約が守られているか継続的にテストする。</li>
<li>会話を続ける。スキーマは生きたドキュメントであって、石版ではありません。</li>
</ol>

<h3 class="relative group">引っかかりどころ
    <div id="引っかかりどころ" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%bc%95%e3%81%a3%e3%81%8b%e3%81%8b%e3%82%8a%e3%81%a9%e3%81%93%e3%82%8d" aria-label="アンカー">#</a>
    </span>
    
</h3>
<p>タダではありません。しっかりしたスキーマを前もって書くには、それなりの時間がかかります。要件が変われば先にスキーマを直す必要があり、その波紋は両チームに及びます。そして全員が、OpenAPIと周辺ツールについて最低限の土地勘を持っている必要があります。</p>
<p>それでも、この先行投資が、防いでくれる統合の混乱に負けたところを見たことがありません。フロントエンドは初日から動き出せますし、議論はビルドが壊れてからではなく、ドキュメントの上で起きるようになります。</p>
]]></content:encoded>
      <media:content url="https://jared.lynskey.co.nz/en/posts/2023/2023-10-08-open-api/featured.jpg" medium="image" type="image/jpeg" />
    </item>
  </channel>
</rss>
