构建类型安全的 API 接口 - OpenAPI 自动成 TS 接口文件

方案

优势

  • 输出规范的 Swagger 接口文档,支持代码生成;
  • 基于 zodjs 生成的 schema,自动的数据校验与类型推导;
  • 基于轻量级的 Honojs 框架,相同的代码支持在所有平台运行;

实现

  1. 使用 zod-openapi 定义一个 OpenAPI 路由
// route.schema.ts
export const ShopProfile = z.object({
  id: z.string(),
  shop: z.string(),
  title: z.string()
}).openapi('ShopProfileVo', {
  description: '商店详情'
});

export const GetShopProfileRoute = createRoute({
  tags: ['Shop'],
  method: 'get',
  path: '/shop/{shopId}',
  request: {
    params: z.object({
      shopId: z.string()
    })
  },
  responses: {
    200: {
      content: {
        'application/json': {
          schema: ShopProfile
        }
      },
      description: 'GetShopProfileRoute'
    }
  }
});
  1. 根据路由 Schema 实现路由
import { OpenAPIHono } from '@hono/zod-openapi'
import { GetShopProfileRoute } from './route.schema.ts'

const api = new OpenAPIHono();

api.openapi(GetShopProfileRoute, async c => {
    const { shopId } = c.valid('params');

    const shopProfile = await prisma.ShopProfile.findUnique({
        where: {
            id: shopId
        }
    })

    return c.json(shopProfile, 200)
})
  1. 生成 Swagger 文件
api.doc('/swagger/doc', (c) => {
    return {
        openapi: '3.1.0',
        servers: [
            {
                url: new URL(c.req.url).origin,
                description: 'Current environment',
            },
        ],
        info: {
            version: '0.0.1',
            title: 'asp-api',
            description: 'asp-api swagger',
        },
    }
})
  1. [可选] 使用 swagger-ui 渲染接口文档

api.get('/swagger/ui', swaggerUI({
    url: '/api/swagger/doc',
    persistAuthorization: true
}))
  1. 使用 swagger-typescript-api 生成 ts 接口文件
// generate.ts
// tsx ./generate.ts
import { generateApi } from 'swagger-typescript-api'

gen();

async function gen() {
    await generateApi({
        name: 'index.ts',
        output: path.resolve(__dirname, 'gen', './api'),
        url: 'http://127.0.0.1:3010/api/swagger/doc',
    })
}