oazapftsでOpenAPI specからTypeScriptクライアントを生成する
OpenAPIからのクライアント生成の老舗といえばOpenAPI Generatorだが、Java実行環境が必要で、テンプレートのメンテナンスなど考えることが多い。oazapftsというもう少しお手頃なジェネレータがあるのでここで紹介する。
特徴
Java不要
TypeScriptで書かれているため、ツールの実行にJavaを必要としない。
HTTPの詳細が露出しない定義
あとで出てくるが、URLのようなHTTPの詳細が見えるタイプのジェネレータとそうでないものがあり、oazapftsは見えない(見えにくいようにする)タイプ。例えばoperations["/pet/1"]ではなく、getPetById
のような関数が生成される。
tree-shakingがされやすい造り
クライアントクラスがありまるごと全部抱えている、みたいなジェネレータもよくあるが、oazapftsは関数で提供する。例えば、以下のように利用可能だ。
import { getPetById } from "./my-generated-api.ts";
このため、bundleされるjsの中に必要な定義のみ取り込むことができる。
この形が嫌であれば、もちろん*でimportしたければしてもいい。
import * as api from "./my-generated-api.ts";
const res = api.getPetById(1);
単体での使い方
インストール
npmからインストールする。
$ npm i oazapfts
ジェネレータ実行
oazapftsコマンドを実行する。
$ oazapfts src/schema/foo-api.yaml src/api/foo-client.ts
package.jsonに入れておくと良い:
"scripts": {
"generate": "yarn run generate:api",
"generate:api": "oazapfts src/schema/foo-api.yaml src/api/foo-client.ts"
},
}
関数を呼ぶ
生成foo-client.tsに関数群が生成されているのでimportして呼べば良い。
import {putDeviceById} from "../api/api-client";
const res = await putDeviceById(deviceId, { priority: values.priority });
if (res.status === 200) {
console.log(res.data);
}
fetch optionはglobalにセットする手段もあるが、引数で渡すのがおすすめ。
const res = await putDeviceById(deviceId, values, {
headers: { "x-hogehoge": 123 }
});
また、毎回エラーチェックするのはしんどいので、"ok"というヘルパーを使うのも良い。
const data = await ok(getDeviceById(deviceId));
ここで書いたのはエラーを自動チェックしないexplicitモードというものだが、optimisticモードにするとチェックして例外にするので、必要に応じて切り替えてもいいかもしれない。が、次に説明するようなヘルパーをアプリケーション用に用意することをおすすめする。
Tanstack Query (React Query)との組み合わせ
Tanstack Queryと組み合わせるのは簡単で、queryFnで呼べば良い。試していないがSWRでも同様のはず。
const {isLoading, isError, data} = useQuery({
queryKey: ["devices"],
queryFn: () => ok(getDevices())
});
ただし、現実的にはContextから値を拾ってヘッダをつけたり、独自のエラーチェックをする処理があったりすると思うので、デフォルトoptionsの提供と、"ok"のようなエラーチェックを行うヘルパー関数をアプリケーション用に用意して一緒に使うことをおすすめする。
const {apiRequest} = useApiHelper();
const {isLoading, isError, data} = useQuery({
queryKey: ["devices"],
queryFn: () => {
// ...
return apiRequest((options) =>
getDevices(options),
);
}
});
TODO: サンプルレポジトリを上げる
他のツールとの比較
OpenAPI Generator
Javaでテンプレートベース。Javaが必要というのもあるが、テンプレートが好みではなく、カスタマイズするとなるとテンプレートのメンテナンスが必要そうなので避けている。
openapi2aspida
TypeScriptの型を使ってtype-safeにHTTPリクエストをしようというツールaspidaのスキーマをOpenAPI specから生成するためのツール。
使う側のコードがOpenAPIのoperationというよりもaspidaスキーマにべったりになりそうというのと、fetch / Tanstack Queryで使いたいのだが、axiosがメインぽく、@aspida/react-queryがあまりメンテナンスされていなそうなのでやめた。
openapi-typescript
OpenAPI specからTypeScriptの型を生成するツール。URLに対して型を生成するので、使う側に生URLが露出する。
例えばこんな感じ:
const findPetsByStatus = fetcher.path("/pet/findByStatus").method("get").create();
const { status, data: pets } = await findPetsByStatus({
status: ["available", "pending"],
});
URLパスはAPIクライアントに閉じていてくれたほうが層として素直であると今の私は考えるので、そこまでwrapしてくれているoazapftsのほうが好ましいと感じている。
oazapftsの意味
The name comes from a combination of syllables oa (OpenAPI) and ts (TypeScript) and is pronounced speaking_head like the Bavarian O'zapt'is! (it's tapped), the famous words that mark the beginning of the Oktoberfest.
https://en.wikipedia.org/wiki/O'zapft_is!
お酒を飲むときの挨拶らしい。私は「おーえー、ざっぷ、えふてぃーえす」と脳内で読んでいる。
Discussion