12 KiB
SDK の生成
FastAPI は OpenAPI 仕様に基づいているため、その API は多くのツールが理解できる標準形式で記述できます。
これにより、最新のドキュメント、複数言語のクライアントライブラリ(SDKs)、そしてコードと同期し続けるテストや自動化ワークフローを容易に生成できます。
本ガイドでは、FastAPI バックエンド向けの TypeScript SDK を生成する方法を説明します。
オープソースの SDK ジェネレータ
多用途な選択肢として OpenAPI Generator があります。これは多数のプログラミング言語をサポートし、OpenAPI 仕様から SDK を生成できます。
TypeScript クライアント向けには、Hey API が目的特化のソリューションで、TypeScript エコシステムに最適化された体験を提供します。
他の SDK ジェネレータは OpenAPI.Tools でも見つけられます。
/// tip | 豆知識
FastAPI は自動的に OpenAPI 3.1 の仕様を生成します。したがって、使用するツールはこのバージョンをサポートしている必要があります。
///
FastAPI スポンサーによる SDK ジェネレータ
このセクションでは、FastAPI をスポンサーしている企業による、ベンチャー支援および企業支援のソリューションを紹介します。これらの製品は、高品質な生成 SDK に加えて、追加機能や統合を提供します。
✨ FastAPI をスポンサーする{.internal-link target=_blank} ✨ ことで、これらの企業はフレームワークとそのエコシステムの健全性と持続可能性を支援しています。
この支援は、FastAPI のコミュニティ(皆さん)への強いコミットメントの表明でもあり、優れたサービスの提供だけでなく、堅牢で発展するフレームワーク FastAPI を支える姿勢を示しています。🙇
例えば、次のようなものがあります:
これらのソリューションの中にはオープンソースや無料枠を提供するものもあり、金銭的コミットメントなしで試すことができます。他の商用 SDK ジェネレータも存在し、オンラインで見つけられます。🤓
TypeScript SDK を作成する
まずは簡単な FastAPI アプリから始めます:
{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}
ここで、path operation はリクエストとレスポンスのペイロードに使用するモデルを定義しており、Item と ResponseMessage を使っています。
API ドキュメント
/docs に移動すると、リクエストで送信・レスポンスで受信するデータのスキーマが表示されます:
これらのスキーマは、アプリ内でモデルとして宣言されているため表示されます。
その情報はアプリの OpenAPI スキーマに含まれ、API ドキュメントに表示されます。
OpenAPI に含まれるこれらのモデル情報を使って、クライアントコードを生成できます。
Hey API
モデルを備えた FastAPI アプリがあれば、Hey API で TypeScript クライアントを生成できます。最も手早い方法は npx を使うことです。
npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client
これで TypeScript SDK が ./src/client に生成されます。
@hey-api/openapi-ts のインストール方法や、生成物の詳細は公式サイトを参照してください。
SDK の利用
これでクライアントコードを import して利用できます。例えば次のようになり、メソッドに対して補完が効きます:
送信するペイロードにも補完が適用されます:
/// tip | 豆知識
FastAPI アプリの Item モデルで定義した name と price に補完が効いている点に注目してください。
///
送信データに対するインラインエラーも表示されます:
レスポンスオブジェクトにも補完があります:
タグ付きの FastAPI アプリ
実運用ではアプリは大きくなり、path operation のグループ分けにタグを使うことが多いでしょう。
例えば items 用と users 用のセクションがあり、タグで分けられます:
{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}
タグ付き TypeScript クライアントの生成
タグを用いた FastAPI アプリからクライアントを生成すると、通常クライアント側のコードもタグごとに分割されます。
これにより、クライアントコードも正しく整理・グルーピングされます:
この例では次のようになります:
ItemsServiceUsersService
クライアントのメソッド名
現状では、生成されるメソッド名(createItemItemsPost など)はあまりきれいではありません:
ItemsService.createItemItemsPost({name: "Plumbus", price: 5})
これは、クライアントジェネレータが各 path operation の OpenAPI 内部の operation ID を用いるためです。
OpenAPI では operation ID は全ての path operation を通して一意である必要があります。そのため FastAPI は関数名、パス、HTTP メソッド/オペレーションを組み合わせて operation ID を生成し、一意性を保証します。
次にこれを改善する方法を示します。🤓
カスタム operation ID とより良いメソッド名
operation ID の生成方法を変更して簡潔にし、クライアント側のメソッド名をシンプルにできます。
この場合でも各 operation ID が一意であることは別の方法で保証する必要があります。
例えば、各 path operation にタグを付け、タグと path operation の名前(関数名)から operation ID を生成できます。
一意 ID 生成関数のカスタマイズ
FastAPI は各 path operation に一意 IDを用いており、これは operation ID のほか、必要に応じてリクエストやレスポンスのカスタムモデル名にも使われます。
この関数はカスタマイズ可能です。APIRoute を受け取り、文字列を返します。
例えばここでは、最初のタグ(通常は 1 つ)と path operation 名(関数名)を使います。
そのカスタム関数を FastAPI の generate_unique_id_function パラメータに渡します:
{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}
カスタム operation ID で TypeScript クライアントを生成
この状態でクライアントを再生成すると、メソッド名が改善されています:
ご覧のとおり、メソッド名はタグ名と関数名のみになり、URL パスや HTTP オペレーションの情報は含まれません。
クライアント生成向けの OpenAPI 仕様の前処理
それでも生成コードには重複情報が残っています。
ItemsService(タグ由来)から items 関連であることはすでに分かるのに、メソッド名にもタグ名が前置されています。😕
OpenAPI 全体としては operation ID の一意性のために、このプレフィックスを維持したい場合があるでしょう。
しかし生成クライアント用には、クライアントを生成する直前に OpenAPI の operation ID を加工して、メソッド名をより見やすく、クリーンにできます。
OpenAPI の JSON を openapi.json として保存し、次のようなスクリプトでそのタグのプレフィックスを除去できます:
{* ../../docs_src/generate_clients/tutorial004_py310.py *}
//// tab | Node.js
{!> ../../docs_src/generate_clients/tutorial004.js!}
////
これにより operation ID は items-get_items のような形から単なる get_items に置き換わり、クライアントジェネレータはより簡潔なメソッド名を生成できます。
前処理済み OpenAPI から TypeScript クライアントを生成
生成元が openapi.json になったので、入力の場所を更新します:
npx @hey-api/openapi-ts -i ./openapi.json -o src/client
新しいクライアントを生成すると、クリーンなメソッド名になり、補完やインラインエラーなどもそのまま利用できます:
利点
自動生成されたクライアントを使うと、次のような対象で補完が得られます:
- メソッド
- 本体のリクエストペイロード、クエリパラメータ等
- レスポンスのペイロード
また、あらゆる箇所でインラインエラーも得られます。
バックエンドコードを更新してフロントエンドを再生成すれば、新しい path operation はメソッドとして追加され、古いものは削除され、その他の変更も生成コードに反映されます。🤓
つまり、変更があれば自動的にクライアントコードに反映されます。クライアントをビルドすれば、使用データに不整合があればエラーになります。
その結果、多くのエラーを開発の初期段階で早期発見でき、本番で最終ユーザーに不具合が現れてから原因をデバッグする必要がなくなります。✨