Hono + OpenAPIの選択肢、実は2つある
HonoでOpenAPIドキュメントを自動生成したい。そう思って調べると、ほぼ確実に@hono/zod-openapiが出てきますよね。
日本語の記事だと、ほぼこの一択で紹介されています。実際、僕も最初はそうでした。
ただ、海外の記事を調べていると、実はもう一つ選択肢があることに気づいたんです。hono-openapiというパッケージで、アプローチがかなり違います。今回は、この2つの違いと使い分けを整理してみます。
@hono/zod-openapi のおさらい
まず、よく知られている@hono/zod-openapiから。
import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi'
const ParamsSchema = z.object({
id: z.string().min(3).openapi({
param: { name: 'id', in: 'path' },
example: '1212121',
}),
})
const UserSchema = z.object({
id: z.string().openapi({ example: '123' }),
name: z.string().openapi({ example: 'John Doe' }),
age: z.number().openapi({ example: 42 }),
}).openapi('User')
const route = createRoute({
method: 'get',
path: '/users/{id}',
request: { params: ParamsSchema },
responses: {
200: {
content: { 'application/json': { schema: UserSchema } },
description: 'Retrieve the user',
},
},
})
const app = new OpenAPIHono()
app.openapi(route, (c) => {
const { id } = c.req.valid('param')
return c.json({ id, age: 20, name: 'Ultra-man' })
})
app.doc('/doc', {
openapi: '3.0.0',
info: { version: '1.0.0', title: 'My API' },
})
見ての通り、OpenAPIHonoという専用クラスとcreateRouteという関数を使います。Zodスキーマに.openapi()でメタデータを付与する形ですね。
この方法の強みは、型安全性が非常に高いこと。ルート定義とバリデーションとOpenAPI生成が完全に統合されています。
ただ、正直なところ、既存のHonoプロジェクトに導入しようとすると、結構な書き直しが必要になります。app.get()をapp.openapi(route, ...)に変えるだけでなく、ルート定義の構造自体が変わるので。
hono-openapi という選択肢
海外の記事で知ったのが、hono-openapiというパッケージです。
こちらは、標準のHonoワークフローをそのまま維持できるのが特徴。
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator'
const app = new Hono()
app.get('/users/:id', zValidator('param', paramSchema), (c) => {
const { id } = c.req.valid('param')
return c.json({ id, name: 'John' })
})
見てください、普通のHonoのコードですよね。OpenAPIHonoもcreateRouteも使っていません。
hono-openapiはミドルウェアとして機能するので、既存のコードにほぼ手を入れずに導入できます。
2つの違いをまとめると
| 観点 | @hono/zod-openapi | hono-openapi |
|---|---|---|
| 構文 | 独自(OpenAPIHono, createRoute) | 標準Hono |
| 学習曲線 | 急(新しいAPIを覚える) | 緩やか(既存知識で対応) |
| 既存プロジェクト | 大規模な書き直しが必要 | 最小限の変更で導入可能 |
| バリデータ | Zodのみ | Zod, Valibot, ArkType, TypeBox |
特にバリデータの選択肢が興味深いです。hono-openapiはZod以外にもValibot、ArkType、TypeBoxをサポートしています。
Valibotは最近海外で人気が出てきているバリデータで、Zodより軽量なのが売りです。もしValibotを使いたいなら、hono-openapiが選択肢に入ってきます。
どっちを選ぶべきか
個人的な見解ですが、こんな感じで使い分けるといいと思います。
@hono/zod-openapi が向いているケース
✓ 新規プロジェクトで最初からOpenAPI前提で設計する
✓ 型安全性を最大限に追求したい
✓ Zodを使うことが確定している
✓ createRouteの構文に抵抗がない
hono-openapi が向いているケース
✓ 既存のHonoプロジェクトにOpenAPIを追加したい
✓ 標準のHono構文を維持したい
✓ Zod以外のバリデータを使いたい
✓ 学習コストを最小限に抑えたい
ぶっちゃけ、新規プロジェクトなら@hono/zod-openapiでいいと思います。型安全性の恩恵は大きいので。
ただ、既存プロジェクトへの導入を考えているなら、hono-openapiのほうが現実的かもしれません。書き直しの手間が全然違います。
OpenAPIからSDKを自動生成する
ここからは、日本ではあまり紹介されていない話。
OpenAPIドキュメントが生成できたら、次に考えたいのがクライアントSDKの自動生成です。
海外ではSpeakeasyというツールがよく使われています。
speakeasy quickstart
このコマンドを実行すると、対話形式でセットアップが進み、TypeScriptやPythonのSDKが自動生成されます。
Speakeasyの特徴は以下の通り。
- OpenAPIドキュメントのLinting:
speakeasy lint openapiでエラーと警告を検出 - AI支援: Speakeasy Suggestで改善提案
- CI/CD統合: GitHub Actionsで自動再生成
- 複数言語対応: TypeScript、Python、Go、Javaなど
海外の事例では「約650時間の開発時間削減」という報告もあります。SDK手書きの工数を考えると、この数字は納得できますね。
日本だとopenapi-typescriptやorvalが有名ですが、Speakeasyも選択肢として知っておいて損はないと思います。
まとめ
HonoでOpenAPIを使うなら、@hono/zod-openapiだけでなくhono-openapiという選択肢もある。
- 新規プロジェクト → @hono/zod-openapi
- 既存プロジェクトへの導入 → hono-openapi
そして、OpenAPIドキュメントができたらSpeakeasyでSDK自動生成、という流れも覚えておくと便利です。
日本語の情報だと@hono/zod-openapi一択になりがちですが、プロジェクトの状況に応じて選んでみてください。