【ITニュース解説】TypeScript devs, don’t let your OpenAPI client generator lie to you.
2025年09月15日に「Dev.to」が公開したITニュース「TypeScript devs, don’t let your OpenAPI client generator lie to you.」について初心者にもわかりやすく解説しています。
ITニュース概要
TypeScriptでOpenAPIクライアントを生成する既存ツールは、型安全性が不十分で、エラーや多様なHTTPレスポンスを正確に扱えない問題がある。これにより、実行時に予期せぬトラブルが発生しやすい。筆者はこの課題を解決するため、より安全で正確な型を提供する新しい生成ツールを開発した。
ITニュース解説
現代のシステム開発では、多くのシステムが「REST API」という標準的なルールで情報をやり取りする。このAPIの設計図を機械が読める形式で記述するのが「OpenAPI」だ。特にTypeScriptでAPIクライアントを開発する際、開発者は「型安全性」を重視する。TypeScriptは、JavaScriptにデータの種類を示す「型」情報を加えることで、プログラム実行前にバグを防ぐ手助けをする。OpenAPIの仕様書からAPIクライアントのコードを自動生成する「OpenAPIクライアントジェネレーター」は、この型安全性を活かし、手作業での型定義の手間を省く便利なツールだ。
しかし、多くの既存のOpenAPIクライアントジェネレーターには、システムエンジニアを目指す初心者が見過ごしがちな落とし穴があり、一見すると型安全に思えても「偽りの安心感」を与え、本番環境で予期せぬ問題を引き起こす可能性がある。
一つの大きな問題は「不十分なエラーハンドリング」である。API呼び出しの型情報が、ネットワークの接続障害やタイムアウトといったネットワークレベルのエラーを考慮していないことが多い。開発者は必ず「try/catch」構文でエラーを捕捉する必要があるが、どのようなエラーが起こり得るかの具体的なドキュメントがないため、推測に頼りがちだ。さらに、APIの仕様違反による入力検証エラーとネットワークエラーが同じ「エラー」として扱われることが多く、これらをプログラム上で適切に区別して対応することが難しい。これにより、効率的なエラー処理が妨げられる。
次に、「HTTPステータスの限定的な扱い」がある。HTTPステータスコードはAPIサーバーからの応答状態を示す3桁の数字で、例えば2xxは成功、4xxはクライアント側のエラー、5xxはサーバー側のエラーを意味する。多くのジェネレーターは、成功応答の「2xx」にのみ型情報を生成し、特定の情報を含む「4xx」や「5xx」のエラー応答を無視してしまう。例えば、不正なリクエストに対してサーバーが「400 Bad Request」と共に何が不正だったかを詳細に記述したエラー情報(ProblemJsonなど)を返しても、そのエラー応答の型が生成されないため、開発者はエラー時のデータ構造を予測できず、実行時に予期せぬ問題に直面する。
さらに、「複数の成功応答に対する限定的な対応」も問題だ。APIによっては、同じ成功の状態でも、異なるHTTPステータスコード(例:200 OKと201 Created)で異なるデータ構造を返すことがある。多くのジェネレーターは、最初の成功ステータスコードにのみ対応し、他の成功ステータスコードが返すデータ構造を適切に型として扱わない。あるいは、それらを区別せずに「このモデルか、または別のモデルのどちらか」といった曖昧なユニオン型としてまとめ、結局開発者が実行時にその型を自分で判断する追加のコードを書くことになる。これではジェネレーターを使う意味が薄れてしまう。
「デフォルト応答の不適切な処理」も看過できない。OpenAPIでは、特定のステータスコードに対応する応答が未定義の場合に備えて「default」という汎用的な応答を定義できる。優れたジェネレーターは、200, 201, 400, 500といった具体的な応答タイプ全てを、それぞれのデータ構造を持つ「判別可能なユニオン型」として生成する。これは、受け取った応答がどのタイプかを判別しやすくするための賢い方法だ。しかし、多くのジェネレーターは、この「default」応答を単なる一般的なエラーとして処理したり、そのペイロード(返されるデータ)の型やバリデーション(妥当性検証)を適切に提供しなかったりする。結果として、本来型情報が得られるはずの応答が、不正確な型として扱われる。
「コンテンツタイプが無視される」という問題もある。APIが同じHTTPステータスコード(例えば200 OK)でも、異なるデータ形式(例えばJSON形式とXML形式)を返す場合がある。開発者はステータスコードだけでなく、返されたデータの「Content-Type」ヘッダー(データ形式を示す情報)を見てどちらのデータ形式か判断し、処理を変える必要がある。しかし、筆者が知る限り、既存のTypeScriptジェネレーターで、ステータスコードとコンテンツタイプという二つの要素に基づいて返されるデータの型を正確に判別し、適切なTypeScriptの型を生成できるものはない。理想的には「ステータスコードが200で、かつコンテンツタイプがapplication/jsonなら、このデータ形式」といった厳密な型推論が期待されるが、現状は難しい。
最後に、「OpenAPIスキーマとTypeScriptの型のミスマッチ」がある。OpenAPIのスキーマ定義は、TypeScriptの型システムよりも表現力が高いことがある。例えばOpenAPIで「この文字列はメールアドレス形式であるべき」といった細かい制約を定義しても、TypeScriptの型では単なる「string」型になってしまい、本来の制約情報が失われる。また「oneOf」(複数のスキーマ定義のうち、いずれか一つに合致する)や「anyOf」(複数のスキーマ定義のうち、一つ以上に合致する)といった高度な結合型も、多くのジェネレーターではTypeScriptの型に適切に変換できなかったり、ランタイム(実行時)のバリデーションが不十分だったりする。これにより、生成された型が不正確になり、結果的に実行時に思わぬバグにつながる可能性がある。
これらの問題点を深く評価した筆者は、既存のトップツールに対して大規模な変更を提案するのではなく、根本的に新しいソリューションを構築する道を選んだ。そして、安全で正確な型情報と優れた開発体験を最優先する、オープンソースのTypeScriptクライアントジェネレーターを自ら開発するに至った。