😽

openapi-fetchで型安全な API クライアントを作る

に公開

軽量でfetch準拠でOpenAPI由来の型推論・補完がそのまま効くopenapi-fetchを使ってみました


パッケージインストール

npm install openapi-fetch
npm install -D openapi-typescript

1) OpenAPIを公開(今回はHonoを使用)

/doc でスキーマを返す。

import { OpenAPIHono } from '@hono/zod-openapi'

export const app = new OpenAPIHono()
app.doc('/doc', {
  openapi: '3.1.0',
  info: {
    title: 'My API',
    version: '1.0.0',
  },
})

2) 型生成(openapi-typescript)

package.jsonにスクリプトを追加:

{
  "scripts": {
    "generate:open-api": "mkdir -p public/openapi/v1 && curl -o public/openapi/v1/openapi.json ${API_URL:-http://localhost:3000}/doc",
    "generate:types": "openapi-typescript public/openapi/v1/openapi.json -o src/types/api/v1/api.d.ts",
    "generate": "npm run generate:open-api && npm run generate:types"
  }
}

スキーマを更新したらnpm run generateを実行して型を再生成します。


3) クライアント(openapi-fetch)

import createClient from 'openapi-fetch'
import type { paths } from '@/types/api/v1/api'

const client = createClient<paths>({ baseUrl: '/api/v1' })

// GET リクエスト
export async function getMemos(limit = 20) {
  const { data, error, response } = await client.GET('/memos', {
    params: { query: { limit } },
  })
  if (error) throw Object.assign(new Error('API Error'), { detail: error, status: response.status })
  return data
}

// POST リクエスト
export async function createMemo(body: { title: string; content: string }) {
  const { data, error, response } = await client.POST('/memos', {
    body,
  })
  if (error) throw Object.assign(new Error('API Error'), { detail: error, status: response.status })
  return data
}

パスの自動補完

client.POST() でパスを入力すると、OpenAPI スキーマから生成された全エンドポイントが補完されます。
パス補完のスクリーンショット

リクエストボディの型チェック

必須プロパティが不足している場合、エディタで即座にエラーが表示されます。
ボディ型エラーのスクリーンショット

レスポンスの型推論

data の型も自動的に推論され、補完が効きます。
レスポンス補完のスクリーンショット


まとめ

openapi-fetchを使うことで、パス/クエリ/ボディ/レスポンスまで補完が効き、仕様変更も型エラーで即検知できる構成にできました。

参考リンク

chot Inc. tech blog

Discussion