如何在Hono Zod-OpenAPI中集成hono/jwt认证中间件的401响应定义?
如何在Hono Zod-OpenAPI中集成hono/jwt认证中间件的401响应定义?
我完全懂你现在的困扰——因为认证中间件是通过app.use全局挂载在受保护路由前缀上的,Zod-OpenAPI没法自动识别中间件可能抛出的401响应,导致你手动在路由里加401响应定义时出现类型错误对吧?
下面给你几个实用的解决方案,都是在实际项目里验证过的:
方案1:复用通用401响应配置
你可以先定义一个包含401响应的基础配置对象,然后在每个受保护路由里合并这个配置,既统一维护又能让类型系统正确识别:
// 定义通用的401响应模板 const protectedRoute401 = { 401: { description: 'Unauthorized', content: { 'application/json': { schema: ErrorSchema, }, }, } as const; // 创建受保护路由时合并模板 router.openapi( createRoute({ method: 'get', path: '/', responses: { 200: { description: 'List all items', content: { 'application/json': { schema: responseSchema(Item), }, }, }, // 合并通用401响应 ...protectedRoute401, }, }), async (c) => { const db = c.get('db'); const res = await db.select().from(items); return c.json({ data: res }); } );
这种方式的好处是不用重复写401响应的代码,所有受保护路由都能共用同一个定义,类型检查也能顺利通过。
方案2:封装自定义的受保护路由创建函数
如果你的受保护路由数量很多,还可以封装一个专属的路由创建函数,把401响应内置进去,进一步简化开发:
import { createRoute, type RouteConfig } from '@hono/zod-openapi'; // 封装带默认401响应的路由创建函数 function createProtectedRoute<T extends RouteConfig>(config: Omit<T, 'responses'> & Partial<Pick<T, 'responses'>>) { return createRoute({ ...config, responses: { 401: { description: 'Unauthorized', content: { 'application/json': { schema: ErrorSchema, }, }, }, // 合并用户自定义的响应 ...config.responses, } as T['responses'], }); } // 使用封装后的函数创建路由 router.openapi( createProtectedRoute({ method: 'get', path: '/', responses: { 200: { description: 'List all items', content: { 'application/json': { schema: responseSchema(Item), }, }, }, }, }), async (c) => { const db = c.get('db'); const res = await db.select().from(items); return c.json({ data: res }); } );
这样你每次创建受保护路由时,不用手动添加401响应,函数会自动帮你加上,代码更清爽,类型安全也有保障。
方案3:通过中间件自动注入401响应(进阶)
如果想实现完全自动化,不用在每个路由里做任何配置,可以写一个自定义中间件,自动给所有受保护路由的OpenAPI文档注入401响应:
import type { MiddlewareHandler } from 'hono'; // 自动注入401响应的中间件 const injectUnauthorizedResponse: MiddlewareHandler = async (c, next) => { // 检查当前路由是否有OpenAPI配置 if (c.route?.openapi) { // 给路由的OpenAPI定义添加401响应 c.route.openapi.responses['401'] = { description: 'Unauthorized', content: { 'application/json': { schema: ErrorSchema, }, }, }; } await next(); }; // 把这个中间件放在认证中间件之后挂载 app.use('/protected/*', authMiddleware, injectUnauthorizedResponse); app.route('/protected', protectedRouter);
这个方法的优势是一劳永逸,所有匹配/protected/*的路由都会自动带上401响应的OpenAPI定义,不用你手动操作。不过要注意,确保ErrorSchema是符合Zod规范的,比如可以这样定义:
import { z } from '@hono/zod-openapi'; const ErrorSchema = z.object({ message: z.string(), code: z.string().optional(), }).openapi('Error');
这样生成的OpenAPI文档就能正确展示401响应的结构啦!
内容来源于stack exchange
相关产品推荐
相关产品推荐

