api-framework-hono

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

API Development with Hono + OpenAPI

使用 Hono + OpenAPI 进行 API 开发

Quick Guide: Use Hono with
@hono/zod-openapi
for type-safe REST APIs that auto-generate OpenAPI specs. Import
z
from
@hono/zod-openapi
(NOT from
zod
) so
.openapi()
is available on all schemas. Always include
operationId
in routes and export the
app
instance for spec generation.

<critical_requirements>
快速指南: 使用 Hono 搭配
@hono/zod-openapi
构建可自动生成 OpenAPI 规范的类型安全 REST API。从
@hono/zod-openapi
导入
z
(而非从
zod
导入),这样所有 schema 都能使用
.openapi()
方法。务必在路由中包含
operationId
,并导出
app
实例以生成规范。

<critical_requirements>

CRITICAL: Before Using This Skill

关键要求:使用本技能前须知

All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type
, named constants)
(You MUST import
z
from
@hono/zod-openapi
, NOT from
zod
-- this gives Zod the
.openapi()
method)
(You MUST export the
app
instance for OpenAPI spec generation)
(You MUST include
operationId
in every route for clean client generation)
</critical_requirements>

Auto-detection: Hono, @hono/zod-openapi, OpenAPIHono, createRoute, Zod schemas with .openapi(), app.route(), createMiddleware, rate limiting, CORS configuration, health checks, hc client, RPC mode, getContext, tryGetContext, contextStorage, some/every/except middleware
When to use:
  • Building type-safe REST APIs with auto-generated OpenAPI specs
  • Defining OpenAPI specifications with automatic Zod validation
  • Creating standardized error responses with proper status codes
  • Implementing filtering, pagination, and sorting patterns
  • Public or multi-client APIs needing formal documentation
  • Production APIs requiring rate limiting, CORS, health checks
When NOT to use:
  • Simple CRUD with no external consumers (framework-native endpoints are simpler)
  • Internal-only APIs without documentation requirements
  • Single-use endpoints with no schema reuse (over-engineering)
Key patterns covered:
  • Modular route setup with
    app.route()
    and
    OpenAPIHono
  • Zod schema definitions with
    .openapi()
    metadata
  • Route definition with
    createRoute
    (operationId, tags, responses)
  • Error handling with named error codes
  • Filtering, pagination, and data transformation
  • Auth, rate limiting, CORS, logging, caching middleware
  • Health check endpoints (shallow and deep)
  • RPC client (
    hc
    ) with end-to-end type safety
  • Context Storage for out-of-handler context access
  • Combine Middleware (
    some
    /
    every
    /
    except
    ) for declarative auth
Detailed Resources:
  • examples/core.md - Route setup, list/detail endpoints
  • examples/validation.md - Zod schema definitions with OpenAPI
  • examples/routes.md - Filtering, pagination, data transformation
  • examples/middleware.md - Auth, rate limiting, CORS, logging, caching
  • examples/error-handling.md - Standardized error responses
  • examples/openapi.md - Spec generation (build-time and endpoint)
  • examples/health-checks.md - Liveness and readiness checks
  • examples/advanced-v4.md - RPC, Context Storage, Combine Middleware
  • reference.md - Decision frameworks, anti-patterns, production checklist

<philosophy>
所有代码必须遵循 CLAUDE.md 中的项目约定(短横线命名、具名导出、导入顺序、
import type
、具名常量)
(必须从
@hono/zod-openapi
导入
z
,而非从
zod
导入——这会为 Zod 提供
.openapi()
方法)
(必须导出
app
实例以生成 OpenAPI 规范)
(必须在每个路由中包含
operationId
,以生成简洁的客户端代码)
</critical_requirements>

自动检测范围: Hono、@hono/zod-openapi、OpenAPIHono、createRoute、带 .openapi() 的 Zod schema、app.route()、createMiddleware、限流、CORS 配置、健康检查、hc 客户端、RPC 模式、getContext、tryGetContext、contextStorage、some/every/except 中间件
适用场景:
  • 构建可自动生成 OpenAPI 规范的类型安全 REST API
  • 通过自动 Zod 验证定义 OpenAPI 规范
  • 创建带有正确状态码的标准化错误响应
  • 实现过滤、分页和排序模式
  • 需要正式文档的公共或多客户端 API
  • 需限流、CORS、健康检查的生产级 API
不适用场景:
  • 无外部消费者的简单 CRUD(框架原生端点更简单)
  • 无需文档的内部专属 API
  • 无 schema 复用的一次性端点(过度设计)
涵盖的核心模式:
  • 使用
    app.route()
    OpenAPIHono
    的模块化路由设置
  • .openapi()
    元数据的 Zod schema 定义
  • 使用
    createRoute
    的路由定义(operationId、标签、响应)
  • 带命名错误码的错误处理
  • 过滤、分页和数据转换
  • 认证、限流、CORS、日志、缓存中间件
  • 健康检查端点(浅度和深度)
  • 具备端到端类型安全的 RPC 客户端(
    hc
  • 用于处理器外上下文访问的 Context Storage
  • 用于声明式认证的组合中间件(
    some
    /
    every
    /
    except
详细资源:
  • examples/core.md - 路由设置、列表/详情端点
  • examples/validation.md - 带 OpenAPI 的 Zod schema 定义
  • examples/routes.md - 过滤、分页、数据转换
  • examples/middleware.md - 认证、限流、CORS、日志、缓存
  • examples/error-handling.md - 标准化错误响应
  • examples/openapi.md - 规范生成(构建时和端点式)
  • examples/health-checks.md - 存活和就绪检查
  • examples/advanced-v4.md - RPC、Context Storage、组合中间件
  • reference.md - 决策框架、反模式、生产环境检查清单

<philosophy>

Philosophy

设计理念

Type safety + documentation from code. Zod schemas serve both validation AND OpenAPI spec generation. Single source of truth flows to clients via generated SDKs or Hono's RPC client.
Use Hono + OpenAPI when: Building public/multi-client APIs, need auto-generated documentation, require formal OpenAPI specs, want type-safe validation.
Use simpler approaches when: Internal-only CRUD, no external API consumers, no documentation needs.
</philosophy>
<patterns>
类型安全 + 代码即文档。Zod schema 同时用于验证和 OpenAPI 规范生成。单一数据源通过生成的 SDK 或 Hono 的 RPC 客户端同步到客户端。
当使用 Hono + OpenAPI: 构建公共/多客户端 API、需要自动生成文档、要求正式 OpenAPI 规范、希望类型安全验证时。
当使用更简单方案: 内部专属 CRUD、无外部 API 消费者、无文档需求时。
</philosophy>
<patterns>

Core Patterns

核心模式

Pattern 1: Modular Route Setup

模式1:模块化路由设置

Structure routes using
app.route()
for modularization. Export the
app
instance for spec generation.
typescript
import { OpenAPIHono } from "@hono/zod-openapi";

const app = new OpenAPIHono().basePath("/api");

app.route("/", jobsRoutes);
app.route("/", companiesRoutes);

// REQUIRED: Export app for spec generation
export { app };
Why good:
app.route()
prevents God files, app export enables build-time spec generation
See examples/core.md for complete setup with framework adapter exports.

使用
app.route()
构建模块化路由结构。导出
app
实例以生成规范。
typescript
import { OpenAPIHono } from "@hono/zod-openapi";

const app = new OpenAPIHono().basePath("/api");

app.route("/", jobsRoutes);
app.route("/", companiesRoutes);

// 必须:导出app以生成规范
export { app };
优势:
app.route()
避免巨型文件,app 导出支持构建时规范生成
查看 examples/core.md 获取包含框架适配器导出的完整设置。

Pattern 2: Zod Schemas with OpenAPI Metadata

模式2:带 OpenAPI 元数据的 Zod Schema

Import
z
from
@hono/zod-openapi
(not
zod
). Use
.openapi()
for schema registration and documentation.
typescript
import { z } from "@hono/zod-openapi";

const MIN_SALARY = 0;
const CURRENCY_CODE_LENGTH = 3;

export const SalarySchema = z
  .object({
    min: z.number().min(MIN_SALARY),
    max: z.number().min(MIN_SALARY),
    currency: z.string().length(CURRENCY_CODE_LENGTH),
  })
  .openapi("Salary", {
    example: { min: 60000, max: 90000, currency: "EUR" },
  });
Why good: importing
z
from
@hono/zod-openapi
provides
.openapi()
automatically, named constants prevent magic number bugs,
.openapi("Name")
registers as
#/components/schemas/Name
See examples/validation.md for complete schema patterns.

@hono/zod-openapi
导入
z
(而非
zod
)。使用
.openapi()
进行 schema 注册和文档化。
typescript
import { z } from "@hono/zod-openapi";

const MIN_SALARY = 0;
const CURRENCY_CODE_LENGTH = 3;

export const SalarySchema = z
  .object({
    min: z.number().min(MIN_SALARY),
    max: z.number().min(MIN_SALARY),
    currency: z.string().length(CURRENCY_CODE_LENGTH),
  })
  .openapi("Salary", {
    example: { min: 60000, max: 90000, currency: "EUR" },
  });
优势:
@hono/zod-openapi
导入
z
会自动提供
.openapi()
,具名常量避免魔法数字错误,
.openapi("Name")
会注册为
#/components/schemas/Name
查看 examples/validation.md 获取完整的 schema 模式。

Pattern 3: Route Definition with createRoute

模式3:使用 createRoute 定义路由

Define routes with
createRoute
and implement with
app.openapi()
. Always include
operationId
.
typescript
import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";

const getJobsRoute = createRoute({
  method: "get",
  path: "/jobs",
  operationId: "getJobs", // Becomes client method name
  tags: ["Jobs"],
  request: { query: JobsQuerySchema },
  responses: {
    200: {
      description: "List of jobs",
      content: { "application/json": { schema: JobsResponseSchema } },
    },
  },
});

app.openapi(getJobsRoute, async (c) => {
  const { country } = c.req.valid("query"); // Type-safe validated params
  // ... handler logic
  return c.json({ jobs: results }, 200);
});
Why good:
operationId
becomes clean client method name (
getJobs
vs
get_api_jobs
),
c.req.valid()
enforces schema validation with types
See examples/core.md for list/detail endpoint examples.

使用
createRoute
定义路由,并通过
app.openapi()
实现。务必包含
operationId
typescript
import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";

const getJobsRoute = createRoute({
  method: "get",
  path: "/jobs",
  operationId: "getJobs", // 成为客户端方法名
  tags: ["Jobs"],
  request: { query: JobsQuerySchema },
  responses: {
    200: {
      description: "职位列表",
      content: { "application/json": { schema: JobsResponseSchema } },
    },
  },
});

app.openapi(getJobsRoute, async (c) => {
  const { country } = c.req.valid("query"); // 类型安全的验证参数
  // ... 处理器逻辑
  return c.json({ jobs: results }, 200);
});
优势:
operationId
会成为简洁的客户端方法名(
getJobs
而非
get_api_jobs
),
c.req.valid()
强制 schema 验证并提供类型支持
查看 examples/core.md 获取列表/详情端点示例。

Pattern 4: Error Handling with Named Codes

模式4:带命名错误码的错误处理

Use named error code constants for consistent, machine-parseable error responses.
typescript
export const ErrorCodes = {
  VALIDATION_ERROR: "validation_error",
  NOT_FOUND: "not_found",
  UNAUTHORIZED: "unauthorized",
  INTERNAL_ERROR: "internal_error",
} as const;
Why good: Named codes enable frontend
switch
handling, consistent shape across all endpoints
See examples/error-handling.md for the full
handleRouteError
utility.

使用命名错误码常量实现一致的、可机器解析的错误响应。
typescript
export const ErrorCodes = {
  VALIDATION_ERROR: "validation_error",
  NOT_FOUND: "not_found",
  UNAUTHORIZED: "unauthorized",
  INTERNAL_ERROR: "internal_error",
} as const;
优势: 命名错误码支持前端
switch
处理,所有端点保持一致的响应格式
查看 examples/error-handling.md 获取完整的
handleRouteError
工具类。

Pattern 5: JWT Authentication with Explicit Algorithm

模式5:带明确算法的 JWT 认证

Always specify the
alg
option on JWT/JWK middleware to prevent algorithm confusion attacks (CVE-2026-22817, CVE-2026-22818, patched in v4.11.4+).
typescript
import { verify } from "hono/jwt";

const JWT_ALGORITHM = "HS256";

const payload = await verify(token, secret, JWT_ALGORITHM);
Why good: explicit algorithm prevents attackers from switching to symmetric verification with known public keys
See examples/middleware.md for complete auth middleware with type-safe variables.
</patterns>
<red_flags>
务必在 JWT/JWK 中间件中指定
alg
选项,以防止算法混淆攻击(CVE-2026-22817、CVE-2026-22818,v4.11.4+ 已修复)。
typescript
import { verify } from "hono/jwt";

const JWT_ALGORITHM = "HS256";

const payload = await verify(token, secret, JWT_ALGORITHM);
优势: 明确的算法可防止攻击者切换为使用已知公钥的对称验证
查看 examples/middleware.md 获取带类型安全变量的完整认证中间件。
</patterns>
<red_flags>

RED FLAGS

警示事项

High Priority:
  • Importing
    z
    from
    "zod"
    instead of
    "@hono/zod-openapi"
    --
    .openapi()
    won't be available
  • Missing
    operationId
    in routes -- generated client has ugly method names
  • Not exporting
    app
    instance -- can't generate OpenAPI spec at build time
  • JWT/JWK without explicit
    alg
    option -- algorithm confusion vulnerability (CVE-2026-22817/22818)
Medium Priority:
  • Using
    c.req.param()
    /
    c.req.query()
    instead of
    c.req.valid()
    -- bypasses Zod validation
  • No pagination limits on list endpoints -- returns massive datasets
  • Generating spec at runtime instead of build time -- wasted CPU per request
  • Not returning proper status codes -- always specify (200, 404, 500)
  • Wildcard CORS (
    "*"
    ) with
    credentials: true
    -- browsers reject this (spec violation)
Gotchas & Edge Cases:
  • c.req.valid("param")
    uses singular
    "param"
    , not
    "params"
    -- easy to mistype
  • In-memory rate limiting doesn't work across multiple instances -- use a shared store
  • CORS middleware must be registered before auth middleware -- OPTIONS preflight bypasses auth
  • ETags should not be used for user-specific data (generates unique ETag per user)
  • RPC routes must be chained (
    .openapi(r1, h1).openapi(r2, h2)
    ) for type inference -- separate calls break it
  • Both client and server
    tsconfig.json
    need
    "strict": true
    for RPC type inference
  • contextStorage()
    middleware must be registered before any code calls
    getContext()
  • Use
    tryGetContext()
    (v4.11.0+) in code that may run outside request context (tests, background jobs)
  • Middleware
    next()
    never throws in Hono -- wrapping
    await next()
    in try/catch is unnecessary
  • getConnInfo
    is adapter-specific -- import from
    hono/bun
    ,
    hono/deno
    ,
    @hono/node-server/conninfo
    , etc. (NOT from
    hono/ip-restriction
    )
</red_flags>

<critical_reminders>
高优先级:
  • "zod"
    而非
    "@hono/zod-openapi"
    导入
    z
    ——
    .openapi()
    方法不可用
  • 路由中缺少
    operationId
    ——生成的客户端方法名不友好
  • 未导出
    app
    实例——无法在构建时生成 OpenAPI 规范
  • JWT/JWK 未指定明确的
    alg
    选项——存在算法混淆漏洞(CVE-2026-22817/22818)
中优先级:
  • 使用
    c.req.param()
    /
    c.req.query()
    而非
    c.req.valid()
    ——绕过 Zod 验证
  • 列表端点未设置分页限制——返回超大数据集
  • 在运行时而非构建时生成规范——每次请求浪费 CPU
  • 未返回正确的状态码——务必指定(200、404、500)
  • 通配符 CORS(
    "*"
    )搭配
    credentials: true
    ——浏览器会拒绝此配置(违反规范)
陷阱与边缘情况:
  • c.req.valid("param")
    使用单数
    "param"
    ,而非
    "params"
    ——容易拼写错误
  • 内存限流在多实例环境下无效——使用共享存储
  • CORS 中间件必须在认证中间件之前注册——OPTIONS 预检请求会绕过认证
  • ETags 不应用于用户专属数据(会为每个用户生成唯一 ETag)
  • RPC 路由必须链式调用(
    .openapi(r1, h1).openapi(r2, h2)
    )以实现类型推断——分开调用会破坏类型推断
  • 客户端和服务端的
    tsconfig.json
    都需要设置
    "strict": true
    以实现 RPC 类型推断
  • contextStorage()
    中间件必须在任何调用
    getContext()
    的代码之前注册
  • 在可能运行于请求上下文之外的代码(测试、后台任务)中使用
    tryGetContext()
    (v4.11.0+)
  • Hono 中的中间件
    next()
    永远不会抛出异常——无需将
    await next()
    包裹在 try/catch 中
  • getConnInfo
    是适配器专属的——从
    hono/bun
    hono/deno
    @hono/node-server/conninfo
    等导入(而非从
    hono/ip-restriction
</red_flags>

<critical_reminders>

CRITICAL REMINDERS

关键提醒

All code must follow project conventions in CLAUDE.md
(You MUST import
z
from
@hono/zod-openapi
, NOT from
zod
-- this gives Zod the
.openapi()
method)
(You MUST export the
app
instance for OpenAPI spec generation)
(You MUST include
operationId
in every route for clean client generation)
Failure to follow these rules will break OpenAPI spec generation and type safety.
</critical_reminders>
所有代码必须遵循 CLAUDE.md 中的项目约定
(必须从
@hono/zod-openapi
导入
z
,而非从
zod
导入——这会为 Zod 提供
.openapi()
方法)
(必须导出
app
实例以生成 OpenAPI 规范)
(必须在每个路由中包含
operationId
,以生成简洁的客户端代码)
不遵循这些规则会破坏 OpenAPI 规范生成和类型安全。
</critical_reminders>