API-First with Hono: OpenAPI to Typed Routes Without Lock-in

API-First with Hono: OpenAPI to Typed Routes Without Lock-in

使用 Hono 实现 API-First:从 OpenAPI 到类型安全路由且无框架绑定

When working with Hono, both code-first and API-first approaches have valid use cases. @hono/zod-openapi is an excellent choice for many teams that prefer a code-first workflow. However, some teams deliberately choose (or are required) to adopt an API-first strategy, where the OpenAPI specification is the Single Source of Truth. This article shows a simple, flexible way to implement API-first with Hono using @apical-ts/craft and a lightweight custom generator.

在使用 Hono 时,代码优先(code-first)和 API 优先(API-first)两种方法都有其适用的场景。对于偏好代码优先工作流的团队来说,@hono/zod-openapi 是一个极佳的选择。然而,一些团队会刻意选择(或被要求)采用 API 优先策略,将 OpenAPI 规范作为“单一事实来源”。本文将展示一种简单且灵活的方法,通过 @apical-ts/craft 和轻量级自定义生成器,在 Hono 中实现 API 优先开发。

Why Some Teams Choose API-First

为什么有些团队选择 API 优先

While code-first is often faster for small-to-medium projects, API-first becomes valuable when you want to keep the door open to potentially switch frameworks in the future. Generally speaking, code-first typically delivers the best developer experience as your consumers are also in the TypeScript ecosystem, but it introduces framework lock-in. API-first requires a code generation step, but gives you more flexibility and independence in the long term.

虽然代码优先在中小项目中通常开发速度更快,但当你希望为未来更换框架保留可能性时,API 优先策略就显得非常有价值。总的来说,代码优先通常能提供最佳的开发体验,因为你的消费者也处于 TypeScript 生态系统中,但它会导致框架绑定。API 优先虽然需要一个代码生成步骤,但从长远来看,它为你提供了更多的灵活性和独立性。

The Sweet Spot: High-Quality Schemas + Full Control

最佳平衡点:高质量 Schema + 完全控制权

You don’t have to sacrifice DX for flexibility. With @apical-ts/craft you can generate Zod v4 schemas and “agnostic” rich route metadata directly from your openapi.yaml, then use a small custom generator to create Hono routes exactly as you want them.

你无需为了灵活性而牺牲开发体验(DX)。借助 @apical-ts/craft,你可以直接从 openapi.yaml 生成 Zod v4 schema 和“与框架无关”的丰富路由元数据,然后使用一个小型自定义生成器,按照你想要的方式创建 Hono 路由。

How It Works

工作原理

  1. Generate Zod schemas and route metadata: npx @apical-ts/craft generate -i ./openapi.yaml -o ./src/generated --routes

  2. 生成 Zod schema 和路由元数据: npx @apical-ts/craft generate -i ./openapi.yaml -o ./src/generated --routes

  3. Transform the metadata with your own generator into clean, idiomatic Hono code. You can bootstrap this generator quickly by describing the desired architecture to an AI coding agent or refer to the existing template in the @apical-ts documentation.

  4. 使用你自己的生成器将元数据转换为简洁、地道的 Hono 代码。你可以通过向 AI 编程助手描述所需的架构来快速启动此生成器,或者参考 @apical-ts 文档中的现有模板。

Here’s an example of a prompt you can use: 以下是一个你可以使用的提示词(Prompt)示例:

Goal: build type safe Hono handlers by first generating route metadata with @apical-ts/craft and then writing a generator that emits the Hono integration. Process:

  1. Run npx @apical-ts/craft generate --routes -i openapi.yaml -o generated.
  2. Inspect generated/routes/* and use them as the only source of truth for operationId, path, method, params, requestMap, and responseMap.
  3. Implement the generator entrypoint in scripts/generate-hono-server.ts.
  4. Implement the generator modules under scripts/hono-generator/* so they read generated route metadata and emit generated/hono/*.
  5. The generator should produce: one generated Hono operation module per route, one handler file per operation for userland code, a register-routes module that mounts routes without a central handlers object, and shared runtime helpers.
  6. Add a runnable Hono server that imports the generated registration layer.

目标: 通过 @apical-ts/craft 生成路由元数据,并编写一个生成器来输出 Hono 集成代码,从而构建类型安全的 Hono 处理程序。 流程:

  1. 运行 npx @apical-ts/craft generate --routes -i openapi.yaml -o generated
  2. 检查 generated/routes/* 并将其作为 operationIdpathmethodparamsrequestMapresponseMap 的唯一事实来源。
  3. scripts/generate-hono-server.ts 中实现生成器入口点。
  4. scripts/hono-generator/* 下实现生成器模块,使其读取生成的路由元数据并输出 generated/hono/*
  5. 生成器应产生:每个路由一个生成的 Hono 操作模块、每个操作一个用户代码处理程序文件、一个无需中央处理程序对象即可挂载路由的注册模块,以及共享的运行时辅助工具。
  6. 添加一个可运行的 Hono 服务器,导入生成的注册层。

Why not let the AI generate the Zod schemas too?

为什么不让 AI 也生成 Zod schema?

Generating high-fidelity Zod schemas from OpenAPI is a surprisingly complex task. It requires deep knowledge of OpenAPI edge cases (discriminators, advanced oneOf/anyOf, nullable + required combinations, complex additionalProperties, XML support, encoding options, etc.). Even modern coding agents struggle to handle all these cases reliably and consistently. That’s why it’s smarter to use a specialized, battle-tested tool that lets you save tokens for the schema generation part, and then let the AI (or yourself) build the lighter, easier to implement, customizable, deterministic framework-specific generator.

从 OpenAPI 生成高保真的 Zod schema 是一项出人意料的复杂任务。它需要对 OpenAPI 的边缘情况(如 discriminators、高级 oneOf/anyOf、nullable + required 组合、复杂的 additionalProperties、XML 支持、编码选项等)有深入的了解。即使是现代的编程助手也很难可靠且一致地处理所有这些情况。因此,更明智的做法是使用经过实战检验的专业工具来处理 schema 生成部分(节省 Token),然后让 AI(或你自己)去构建更轻量、易于实现、可定制且确定性的框架特定生成器。

Example Handler (strongly typed)

处理程序示例(强类型)

import type { AddPetHandler } from "../../generated/hono/operations/addPet.js";

export const addPetHandler: AddPetHandler = async (input) => {
  const pet = await petService.create(input.body);
  return {
    status: "200",
    contentType: "application/json",
    data: pet,
  };
};

The generated handler type ensures that your business logic remains perfectly aligned with your contract. The handler receives an input object containing already validated body, query, headers, and path parameters. In addition, the return type is strictly enforced at compile-time: you must return a valid combination of status, contentType, and data as defined in your OpenAPI specification.

生成的处理程序类型确保了你的业务逻辑与契约保持完美一致。处理程序接收一个输入对象,其中包含已经过验证的 body、query、headers 和路径参数。此外,返回类型在编译时受到严格限制:你必须返回 OpenAPI 规范中定义的 status、contentType 和 data 的有效组合。

Main Advantages of This Approach

此方法的主要优势

  • OpenAPI stays as the source of truth

  • High-quality Zod schemas (Zod v4)

  • Full control over your Hono architecture, middleware, error handling, and folder structure

  • Minimal lock-in: you own the translation layer

  • Easy to add refinements, transformations, and custom logic on top of generated schemas

  • Strong type safety

  • OpenAPI 始终作为事实来源

  • 高质量的 Zod schema (Zod v4)

  • 对 Hono 架构、中间件、错误处理和文件夹结构拥有完全控制权

  • 最小化绑定:你拥有转换层的所有权

  • 易于在生成的 schema 之上添加优化、转换和自定义逻辑

  • 强大的类型安全

Ready-to-use Example: https://github.com/gunzip/apical-ts/tree/main/examples/hono