📌
openapi-ts で生成する 型定義と OpenAPI Client
はじめに
OpenAPI の定義から OpenAPI Client を生成するツールといえば、openapi-generatorがメジャーですが、動作させるために Java または Docker が必要となるため扱いづらいと感じていました。
また、Client/Server で様々な言語/FW に対応しているため必要な情報が調べにくく、またオプションや構文の対応状況に差異があり別ターゲットのナレッジが使いまわしにくい印象でした。
代替として、openapi-typescript と openapi-fetch が良さそうなので、使い方を見ていこうと思います。
前提
OpenAPI の定義は、Swagger が公開しているサンプルを利用します。
導入
openapi-typescript
openapi-typescript をインストールします
$ npm i -D openapi-typescript
生成のための scripts を追記します
package.json
{
// ...
"scripts": {
// ...
+ "pregenerate": "npm run clean:generate",
+ "generate": "openapi-typescript https://petstore3.swagger.io/api/v3/openapi.json -o ./src/generated/oas.d.ts",
// ...
+ "clean:generate": "node -e 'fs.rmSync(`src/generated`, {recursive:true, force:true})'",
// ...
},
"devDependencies": {
// ...
+ "openapi-typescript": "^6.7.4",
// ...
"typescript": "^5.3.3"
// ...
}
}
型定義を生成します。
$ npm run generate
#ref を利用している場合
@redocly/cli を利用し、事前に OpenAPI 定義を 1 ファイルにまとめます
$ npm i -D @redocly/cli
package.json
{
// ...
"scripts": {
// ...
+ "oas": "redocly bundle [エントリポイントのOpenAPIファイル] --output [出力先]",
// ...
"pregenerate": "npm run clean:generate",
+ // ↓入力をoasの出力先に合わせる
"generate": "openapi-typescript https://petstore3.swagger.io/api/v3/openapi.json -o ./src/generated/oas.d.ts",
// ...
+ "clean:oas": "node -e 'fs.rmSync(`oas`, {recursive:true, force:true})'",
"clean:generate": "node -e 'fs.rmSync(`src/generated`, {recursive:true, force:true})'",
// ...
},
"devDependencies": {
// ...
"openapi-typescript": "^6.7.4",
// ...
"typescript": "^5.3.3"
// ...
}
}
$ npm run oas
$ npm run generate
openapi-fetch
openapi-fetch をインストールします
$ npm i openapi-fetch
client の作成
src/client.ts
import createClient from 'openapi-fetch';
import type { paths } from './generated/oas';
// -----
/**
* Client
*/
export const client = createClient<paths>({
baseUrl: `https://petstore3.swagger.io/api/v3`,
});
// -----
APi の呼び出し
const {
data, // only present if 2XX response
error, // only present if 4XX or 5XX response
response,
} = await client.GET("/pet/findByStatus", {
params: {
query: {
status: "available",
},
},
});
console.log("data", data);
console.log("error", error);
const {
data, // only present if 2XX response
error, // only present if 4XX or 5XX response
response,
} = await client.GET("/pet/{petId}", {
params: {
path: {
petId: 10,
},
},
});
console.log("data", data);
console.log("error", error);
const {
data, // only present if 2XX response
error, // only present if 4XX or 5XX response
response,
} = await client.POST("/pet", {
body: {
id: 10,
name: "doggie",
category: {
id: 1,
name: "Dogs",
},
photoUrls: ["string"],
tags: [
{
id: 0,
name: "string",
},
],
status: "available",
},
});
console.log("data", data);
console.log("error", error);
利用例
型定義の取得
import type { components } from "./generated/oas";
type schemas = components["schemas"];
type responses = components["responses"];
type parameters = components["parameters"];
type requestBodies = components["requestBodies"];
type headers = components["headers"];
type pathItems = components["pathItems"];
認証ヘッダーの付与
import createClient from "openapi-fetch";
import type { paths } from "./generated/oas";
// -----
/**
* Client
*/
export const client = createClient<paths>({
baseUrl: `https://petstore3.swagger.io/api/v3`,
fetch: async (
input: string | URL | globalThis.Request,
init?: RequestInit
): Promise<Response> => {
const token = "";
return fetch(input, {
...init,
headers: new Headers({
...init?.headers,
Authorization: `Bearer ${token}`,
}),
});
},
});
// -----
レスポンスヘッダーの取得
const { data, error, response } = await client.GET("/pet/findByStatus", {
params: {
query: {
status: "available",
},
},
});
console.log("headers", response.headers);
さいごに
しっかり型補完が聞きつつも、シンプルな構成なため、要件に応じてカスタマイズできるため、推せるライブラリでした。
Discussion