メインコンテンツにジャンプ
開発 モバイル

OpenAPI TypeScript: 型、クライアント、検証の生成

OpenAPI TypeScript の生成方法を端から端まで学びましょう。型を生成し、クライアントを接続し、実行時には検証し、CI から安全に配布してください。

マーティン・ドナディュー

マーティン・ドナディュー

コンテンツマーケター

OpenAPI TypeScript: 型、クライアント、検証の生成

通常、API_PIPELINE がチームに嘘を言う瞬間を認識できます。スキーマが変更され、生成された型は苦情を言わずに更新され、PR が緑色になり、そしてフロントエンドの誰かが古いレスポンスの形を読み続けているのは、ラッパーがエラーを無視したからです。そののは OpenAPI TypeScript の問題であり、ジェネレータがインターフェイスを吐き出す能力ではなくて、問題はそこにあります。

実際に役に立つ質問は、より難しいものです。スキーマ、トランスポート、検証の間の契約をどのように設定し、どの部分がビルド時ではなく実行時で失敗するべきか、そしてどの部分が失敗するべきかを決定することです。そうしたフレームワークを立てることで、 OpenAPI TypeScript パイプラインの選択肢として、トレードオフがはっきりし、ツールが全体の解決策であると装うのをやめます。

目次

生成された型は安全なAPIと同じではありません

チームメンバーがオプションのレスポンスフィールドを追加するPRをマージします。生成されたファイルはきれいに更新され、diffは面白くありません。すると、フロントエンドは「一時的に」キャストされた手書きのラッパーを通して古い形を読み続けます。 as anyそして、プロダクションは契約が変更されたことのように振る舞い始めます。

生成された型の罠です。 TypeScriptは生成された型を消費するcodeを保護できますただし、トランスポート層が契約を再度消去しない限りです。OpenAPI側はスキーマを提供しますが、すべてのコールャーがそれを尊重する保証はありません。 生成された型のAPI接続を理解する議論 __CAPGO_KEEP_0__はここで役に立つ。なぜなら、会話を単一のツールからシステムの接続方法へと移すからだ。

__CAPGO_KEEP_0__はどこに隠れているのか

最も一般的なブレークポイントは、珍しいものではなく、面白くないものだ。 スキーマのずれ スキーマのずれは、OpenAPIの仕様と実際にデプロイされたサービスが一致しないときに発生する。 部分的なカバレッジ 部分的なカバレッジは、仕様がハッピーパスのみをモデル化しているのに対し、実際のアプリは未記載のエッジケースに依存している場合に発生する。 手書きのラッパー 手書きのラッパーは、特に「速く進む」ことを望む人にとっては、型が弱まることが多い。そうするのは、 any または、緩いレスポンスのキャストを使うことだ。

実用的なルール ラッパーが嘘をつくことができる場合、ジェネレータはあなたを救うことができない。

There’s also a runtime gap. TypeScript types disappear after compilation, so they can’t reject malformed JSON coming over the wire. The network does not care what your editor inferred, and that’s why a generated client is only one layer in a safer API pipeline.

より広い運用上の質問は、セキュリティと契約の規範、開発者にとっての便利さだけではありません。 API コントラクトがより大きなアプリケーション ライフサイクルにどのように整合するかを、構造化されたビューで理解したい場合は、この内部ガイド API アプリ ストアの準拠性のためのセキュリティ スタンダード は、有用なパートナーです。

成熟した方法で考えると、openapi typescriptは次のようになります。 厳格なスキーマから型の橋渡しを提供することは素晴らしいですが、要求を検証せず、実行時ペイロードの形状を強制せず、粗末なラッパーが全てを覆い隠すことはありません。ジェネレータは簡単な20%ですが、パイプラインの設計が残りの80%です。チームは信頼を得るか、誤った自信を蓄積するかで決まります。 OpenAPI SpecからTypeScriptの型を生成する

https://openapi-ts.devからスクリーンショット

最も軽量で有用なセットアップは、実際のリポジトリの変化に耐えられることが多いです。OpenAPI specを同じリポジトリに保ち、コミットされた型ファイルを生成し、CIでドリフトを可視化するのではなく、誰かがリフレッシュステップを思い出す必要がなくなるようにします。コマンド

は、レビューアが他のソース変更と同様に検査できるように、決定的な出力ファイルを提供します。 npx openapi-typescript ./openapi.yaml -o ./src/types/api.d.ts 実際に重要なフラグ

__CAPGO_KEEP_0__

The output flag is important because it makes the generated artifact explicit. -o は、生成された型を出力に readonly の意図を保持するために役立ちます。また、スキーマの順序が意味のない変更で変わっても diff が安定するため、 --immutable は、生成された表面に enum を使用することを好むチームにとって重要です。 --alphabetize プロジェクトのドキュメントは、スコープが明確であることを明確に述べています。生成された型のジェネレータであり、クライアントランタイムやリクエストレイヤーではありません。この制限は、軽量で型を優先するセットアップを求める場合に役立ちます。 --enum リポジトリも、ツールのメンテナンスモデルを示しています。これは、ドキュメントやリリースが活発に更新されている場合にオープンソースツールが実用的なメンテナンスを続ける理由です。

オープンソースメンテナンスのケースについての議論は、 のリポジトリとのドキュメントを参照してください。 Wire generation を__CAPGO_KEEP_0__ GitHub repository and CLI documentation.

に統合してください。 package.json CIでビルドスクリプトの他の部分とともにコマンドが存在するので、仕様が変更されたときに常に実行します。CIでファイルを再生成し、 git diff ドリフトが表示される場合は失敗します。契約変更を可視化されたレビュー作業に変えるのではなく、静的な実行時リスクに変えるのです。

コマンドラインのスキーマ側もコマンドラインと同等に重要です。プロジェクトでは compilerOptions.noUncheckedIndexedAccess の使用を推奨しています。 additionalProperties の使用を推奨しています。 T | undefinedの使用を推奨しています。 oneOf の使用を推奨しています。 $defs の使用を推奨しています。 openapi-typescript の使用を推奨しています。 anyの使用を推奨しています。

の使用を推奨しています。

の詳細を明示的に指定しないと、生成された出力から消えてしまう可能性があります。時間を節約するために、1つの詳細を追加するだけで済みます。

純粋型とフルクライアント、そしてコードジェネレーションなしの選択

パターン ビルド時 出力ファイル バンドル重量 最適な選択
純粋型とスリムラッパー 高速 少数 コードジェネレーションなしの制御と小さな実行時サーフェイスを望むチーム
フルクライアントコードジェネレーション 遅い 多くの 高い 迅速なハンドオフと自動生成されたオペレーションを望むチーム
コード生成要求ビルダーなし 速い 何もまたは最小限の 低い 1つのコードベースのアプリケーションが手書きのトランスポートロジックを好む

APIが見る中断の量に関係なく、どのツールが勝つかということではなく、どのパイプラインの形がリポジトリ、チーム、に合っているかということです。 2025年のベンチマークでは、約, openapi-typescript 75,000行、2MB、約1,200オペレーションの大きさのOpenAPI仕様について 1.5秒 __CAPGO_KEEP_0__の平均で、約 8.0秒 の場合 @hey-api/openapi-ts, 5.5秒 の場合 Orval, および 18.1秒 の場合 Kubb, 1つの出力ファイルを生成する 16 の場合 hey-api, 2,719 の場合 Orval、そして 3,877 開発者用の Kubb (ベンチマーク詳細).

純粋な型は制御を優先します

純粋な型の設定は、ハンドメイドのリクエスト層と組み合わせると、実行時を小さくし、API サーフェスを単純化できるため、バンドラーに敏感なフロントエンドと、スペックと消費者を同じチームが所有するアプリでは役立ちます。開発者体験が単にシンタックス糖分だけではないことを思い出させる必要がある場合は、 開発者体験の角度 クライアントcodeが短く明確で、レビューできる場合、判断が容易になります。

フルクライアントはハンドオフのスピードを優先します

openapi-generator, hey-api, Orval、そして Kubb すべては型を超えて行うことを試みています。そうすることで、リクエストメソッド、モデル、パイプラインを一緒に生成できるのが役立ちます。特に、バックエンドとフロントエンドのチーム間で大きなハンドオフが必要な場合です。コストは明らかです。ベンチマーク上の表からもわかります。生成されたファイルが増え、実行時サーフェスが大きくなり、スペックが大きくなるとビルドの摩擦が生じます。

コード生成をしない方がローカルにリファクタリングが簡単

型付きのリクエストビルダーと fetch wrapperは、両端の形状を所有するコードベースが一つで、APIの変更が密接に調整されている場合にうまく機能します。欠点は、メンテナンスの規律です。生産者と消費者の間にあるチームとリポジトリが増えると、手動で要求層を維持する可能性が高くなります。除外する必要がある場合、契約テストを積極的に強制する必要があります。

核心的な決定点は、イデオロギー的なものではありません。バンドル予算が限られている場合、純粋な型は魅力的です。チームが最大限のサボテージングを望み、出力を吸収できる場合、フルクライアントはセットアップ時間を短縮できます。契約を近く保つことができ、最小限の動作部品が必要な場合、ノーコードジェン request ビルダが適切な内部取引になる可能性があります。

FetchまたはAxiosを使用した薄い型付きクライアントのワイヤリング

生成されたTypeScript API定義を使用したTyped Client Wrapperプロセスの図示。

生成器が停止し、Application codeが始まる場所は薄いラッパーです。ラッパーは、1つの操作ごとに1つの関数を公開し、型付きパラメーターとクエリオブジェクトを受け取り、呼び出しを fetch またはインジェクションされた axios インスタンスに転送することなく、賢くないことを試みないでください。ほとんどの生産環境では、その層は 30–60行 生成された型が形状のほとんどを含んでいるためです。

ここに、持続するメンタルモデルがあります。

  • パスパラメーターは型付きで so /users/{id} 実行できない id.
  • クエリオブジェクトは型付きで残ります オプションのフィルタが文字列のスープに変わりません。
  • レスポンスボディは型付きで残ります codeのパースは、期待する狭い形状を信頼できるので、信頼できます。

そのようなラッパーは意図的に面白くありません。リトライ、変換、または認証ポリシーを発明しないでください。そういったものはどこかの他の場所に属するものです。型付きの操作からリクエストを移動し、型付きの結果を上に返すだけです。

ラッパーを面白くしないでください。依存性が軽いままにしてください。将来のコードジェネレータの変更があれば、すべてのアプリに波及効果が生じます。

共通の失敗は、生成された型が古いラッパー署名と一致しない場合に、 as any を使用して、不一致をパッチすることです。そうすると、緑のビルドと脆弱なアプリが得られます。生成器が明らかにした契約違反も隠します。

Axiosを使用するチームの場合、パターンは同じですが、トランスポート実装が変更されます。ブラウザ側のcodeがより単純になりたいチームの場合、 fetch はよくありません。重要なのは、生成されたパス型を受け取るリクエスト関数と、後でマッサージされる文字列オブジェクトではなく、型付きのレスポンスを返すことです。

このシームをうまく利用する場合、 openapi typescript は労働の分割をきれいに実現します。スキーマは仕様内にあり、トランスポートはラッパー内にあり、そしてアプリは型付きの操作を表示するのではなく、不定の要求codeを表示します。

zod、ajv、またはio-tsを使用したランタイム検証の追加

TypeScriptの型は実行時には消え、ネットワークはエディターの信頼性を気にしません。なぜなら、安全なパターンは「型を生成し、希望する」というものではなく、「型を生成し、エッジで不信任のデータがアプリに流入するところで検証する」というものだからです。生成されたスキーマは真実の源であり、検証ライブラリとして zod, ajvio-ts は、コンパイル時型が実行できない境界チェックを処理します。

データが入る場所で検証する

Reactアプリの場合、エッジは通常、要求が解決した直後であり、ペイロードがステートに入る前にあります。サーバーの場合、ペイロードがデータベースに書き込まれる前に、またはビジネス ルールに渡される前にあります。ルールは単純です。検証を境界近くに保ち、機能codeを散らすことなく、手動のチェックを散らすことなく。

A zod の形状は、生成されたレスポンスの形状を反映することができますが、置き換えることはありません:

import { z } from "zod";

const WeatherForecastSchema = z.object({
  date: z.string(),
  temperatureC: z.number(),
  summary: z.string().nullable(),
  temperatureF: z.number().optional(),
});

この例では、スキーマがオプションとしてマークしたフィールドを検証し、実行時チェックを生成元と同期しています。 ajv は、サーバー上で高スループットのJSONスキーマ検証を実現するのに強い選択肢です io-ts まだ、既存のチームがすでに同様のスタイルで作業している場合に適合する。 fp-ts 構成のスタイル。

大きな間違いは、データがアプリケーションに最初に到達する前に、データを検証することです。データがアプリケーションに到達すると、型システムはすでにバイパスされ、バグは隠れ場所を見つけることができます。 JavaScriptのユニットテストの短いガイド この考え方と組み合わせると、どちらもユニットテストと境界検証が、悪い仮定を早く捕まえることで最も効果的であることを示しています。

クリーンレイヤーは予測可能です。 OpenAPI TypeScript 契約を生成し、バリデータが実行時データをチェックし、アプリケーションはcodeで両方のステップを通過したデータのみを参照する。静的タイプが不信頼性のあるレスポンスを監視するのではなく、契約を警察するのと比べると、境界ははるかに良くなります。

CIにGeneration、Validation、Contractテストを配置する

https://github.comからスクリーンショット

パイプラインが長く続くと、契約をゲートに変え、提案ではありません。生成器のバージョンを固定し、ドリフトで失敗し、__CAPGO_KEEP_0__の形状をモックまたは契約ツールで実行し、マージする前に tsc --noEmitバージョンを固定し、ドリフトで失敗し、APIの形状をモックまたは契約ツールで実行し、 package.json, 2つのエンジニアが同じ仕様から異なる出力を意図せずに生み出すことはできない。

A simple GitHub Actions 形式

実用的ワークフローは次のようになります。

  1. リポジトリまたは生成されたソースから仕様を取得する。
  2. 型を再生成する。
  3. もしも git diff shows 変更。
  4. Run tsc --noEmit.
  5. 実行用の契約テストを、Prism または Spectral でバックアップされたチェックを使用したモックサーバーで実行する。

契約テストとスナップショットテストの主な違いは範囲です。スナップショットはファイルが変更されたことを教えてくれますが、契約テストは仕様が何を示しているかを教えてくれます。

モックサーバーは、バックエンドとフロントエンドの作業が時間やチームの境界によって隔てられている場合に特に便利です。顧客 code に予測可能な API サーフェイスを提供し、実際の契約ではなく固定されたフィクスチャをチェックするのではなく、実際の契約をチェックすることができます。 継続的インテグレーション設定ガイド は、チームがクリーンで繰り返し可能なCI基準を必要としている場合に役立つ参考資料です。

生成器のバージョンを固定することで、コードジェネレータのパイプラインにおける最もひどい失敗の1つである、不可視の出力偏差を回避できます。開発者がローカルに生成器をアップグレードした場合、もう一人の開発者がアップグレードしない場合、生成されたファイルはランダムなノイズの源となるのではなく、信号となるはずです。CIはそのようなことは不可能にすべきです。

結果として、スキーマの変更、型生成、コンパイラのチェック、契約テストがすべて相互に強化されるパイプラインが得られます。それがワークフローの正直さを生み出します。

維持可能なパイプライン、パフォーマンス、最終チェックリスト

ソフトウェア開発プロジェクトのオープンAPI TypeScript パイプラインの維持のための4つの重要なステップを示すチェックリストです。

The pipelines that survive are the ones with boring governance. Version the spec, review schema changes like code, pin the generator, and document how breaking changes get approved. If the process is fuzzy, people will route around it, and then the generated types become decoration instead of enforcement.

実際には、パフォーマンスのいくつかのレバーが実際に重要です

モノレポでスキーマが頻繁に変更されるが、しかもそれをConsumingするのは1つのパッケージだけの場合、インクリメンタルジェネレーションは役立ちます。 tsc --incremental 再帰的なコンパイラの作業を省略し、生産ビルドで必要ない出力フラグを無効にすることで、生成された表面を小さくすることができます。実際には、最も大きな勝利は依然として社会的、技術的ではなく、予測可能なパイプラインが実行される頻度が、賢いパイプラインよりも多くなります。

以下のチェックリストは、最も価値のあるものです。

  • バージョン固定: 生成器のバージョンを固定することで、不可視の出力偏差を回避できます。 openapi-typescript バージョン package.json その出力は、機器間でずれを防ぐようにする。
  • スキーマレビュー: 仕様変更をレビュー可能な契約変更として扱い、メンテナンス作業として扱わない。
  • ずれ検出: CIで再生成し、差分があれば失敗する。
  • エッジ検証: 不信頼できるペイロードをアプリケーション状態や永続化に到達する前にパースする。
  • 契約テスト: モックバックされたチェックを実行し、消費者codeがスキーマと一致することを証明する。
  • 破壊的変更ポリシー: 形状変更を承認する人と、クライアントに通知する方法を書き留める。

パイプラインに含まれるゲートは、タイプを生成するだけでなく、契約を表示します。この可視性は、ファイルが安全にしか見えなくてもチームがファイルを信頼しないようにします。

If you’re shipping Capacitor or Electron apps and you want your update pipeline to behave with the same discipline, Capgo gives you a practical way to move JavaScript, CSS, copy, config, and asset fixes quickly without waiting on app store review. Visit Capgo Capgoの署名バンドル、ロールバック保護、リリースコントロールは、速度が必要なリリースプロセスに適合するように見せます。

Capacitor アプリのリアルタイム更新

ウェブ層のバグが生じた場合、Capgo を使用して修正を配信し、アプリストアの承認待ちの日数を待たずに修正を配信する。ユーザーはバックグラウンドで更新を受け取り、ネイティブの変更は通常のレビュー経路で残る。

今すぐ始める

ブログの最新記事

Capgo を使用すると、プロフェッショナルなモバイルアプリを作成するために必要な最良の洞察を得ることができます。