Hono + Zod + OpenAPI で Swagger UI を自動生成する

スポンサーリンク

Hono + Zod + OpenAPI で Swagger UI を自動生成する

Hono は軽量な TypeScript 向け Web フレームワークです。@hono/zod-openapi を使うと、Zod スキーマを書くだけで OpenAPI 仕様(Swagger)が自動生成されます。APIドキュメントを手書きする必要がなくなります。


早わかりまとめ

役割 担当
Web フレームワーク Hono
スキーマ定義・バリデーション Zod
OpenAPI 仕様の生成 @hono/zod-openapi
Swagger UI の表示 @hono/swagger-ui

インストール

npm install hono @hono/zod-openapi @hono/swagger-ui zod

基本セットアップ

// src/index.ts
import { OpenAPIHono } from '@hono/zod-openapi'
import { swaggerUI } from '@hono/swagger-ui'

const app = new OpenAPIHono()

// Swagger UI を /ui で表示
app.get('/ui', swaggerUI({ url: '/doc' }))

// OpenAPI JSON を /doc で配信
app.doc('/doc', {
  openapi: '3.0.0',
  info: {
    version: '1.0.0',
    title: 'My API',
  },
})

export default app

ルートを定義する

// routes/users.ts
import { createRoute, z } from '@hono/zod-openapi'

// レスポンスのスキーマ
const UserSchema = z.object({
  id: z.number(),
  name: z.string(),
  email: z.string().email(),
})

// パラメータのスキーマ
const ParamsSchema = z.object({
  id: z.coerce.number(),
})

// ルート定義
export const getUserRoute = createRoute({
  method: 'get',
  path: '/users/{id}',
  request: {
    params: ParamsSchema,
  },
  responses: {
    200: {
      content: {
        'application/json': {
          schema: UserSchema,
        },
      },
      description: 'ユーザー情報を返す',
    },
    404: {
      description: 'ユーザーが見つからない',
    },
  },
})

ルートをアプリに登録する

// src/index.ts
import { OpenAPIHono } from '@hono/zod-openapi'
import { getUserRoute } from './routes/users'

const app = new OpenAPIHono()

app.openapi(getUserRoute, (c) => {
  const { id } = c.req.valid('param')
  // id は number 型(Zod でバリデーション済み)

  const user = { id, name: 'Alice', email: 'alice@example.com' }

  return c.json(user, 200)
})

POST リクエストのスキーマ例

const CreateUserSchema = z.object({
  name: z.string().min(1, { message: '名前を入力してください' }),
  email: z.string().email({ message: 'メールアドレスの形式が正しくありません' }),
})

export const createUserRoute = createRoute({
  method: 'post',
  path: '/users',
  request: {
    body: {
      content: {
        'application/json': {
          schema: CreateUserSchema,
        },
      },
    },
  },
  responses: {
    201: {
      content: {
        'application/json': {
          schema: UserSchema,
        },
      },
      description: 'ユーザーを作成した',
    },
  },
})

// ハンドラー
app.openapi(createUserRoute, async (c) => {
  const body = c.req.valid('json')
  // body は { name: string; email: string } 型(型安全)

  const newUser = { id: 1, ...body }
  return c.json(newUser, 201)
})

生成される Swagger UI

http://localhost:3000/ui にアクセスすると Swagger UI が表示されます。スキーマに書いた内容が自動的にドキュメント化されます。

GET  /users/{id}  ユーザー情報を返す
POST /users       ユーザーを作成した

リクエスト・レスポンスのスキーマ、バリデーション、型が1か所にまとまります。


まとめ

やること コード
アプリ作成 new OpenAPIHono()
ルート定義 createRoute({ method, path, request, responses })
ルート登録 app.openapi(route, handler)
OpenAPI JSON を配信 app.doc('/doc', { openapi: '3.0.0', ... })
Swagger UI を表示 app.get('/ui', swaggerUI({ url: '/doc' }))
バリデーション済み値を取得 c.req.valid('param') c.req.valid('json')

Zod の基本的なスキーマ定義については「Zod 入門:z.object・z.infer・safeParse の使い方」を参照してください。