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のコードですよね。OpenAPIHonocreateRouteも使っていません。

hono-openapiはミドルウェアとして機能するので、既存のコードにほぼ手を入れずに導入できます。

2つの違いをまとめると

観点@hono/zod-openapihono-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一択になりがちですが、プロジェクトの状況に応じて選んでみてください。