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 の使い方」を参照してください。