如何结合TypeBox与Inversify路由在swagger-express-ts中复用模型?
解决方案
1. 核心思路:TypeBox Schema 转 Swagger 兼容结构
swagger-express-ts 的装饰器(如@ApiRequestBody、@ApiResponse)接受的是符合 Swagger 规范的 JSON Schema,而 TypeBox 自带了将自身 Schema 转换为标准 JSON Schema 的方法,利用这一点就能实现复用。
2. 具体实现步骤
第一步:定义复用的 TypeBox Schema
先写出通用的 TypeBox 校验 Schema,后续在校验和 Swagger 装饰器中都用这个:
import { Type } from '@sinclair/typebox'; // 可复用的用户创建参数Schema const CreateUserSchema = Type.Object({ username: Type.String({ minLength: 3, maxLength: 20 }), email: Type.String({ format: 'email' }), password: Type.String({ minLength: 6 }) }); // 可复用的用户返回结果Schema const UserResponseSchema = Type.Object({ id: Type.String(), username: Type.String(), email: Type.String() });
第二步:转换 Schema 并在 Swagger 装饰器中使用
使用 TypeBox 的SchemaToJsonSchema方法转换后,直接传入 swagger-express-ts 的装饰器参数:
import { ApiOperationPost, ApiRequestBody, ApiResponse } from 'swagger-express-ts'; import { SchemaToJsonSchema } from '@sinclair/typebox'; import { Post, Req } from 'inversify-express-utils'; @ApiOperationPost({ path: '/users', description: '创建新用户', summary: '用户注册接口' }) @ApiRequestBody({ description: '用户注册参数', required: true, // 转换TypeBox Schema为Swagger兼容结构 schema: SchemaToJsonSchema(CreateUserSchema) }) @ApiResponse({ statusCode: 201, description: '创建成功', schema: SchemaToJsonSchema(UserResponseSchema) }) @Post('/users') async createUser(@Req() req: Request) { // 这里用TypeBox做参数校验 const isValid = Type.Check(CreateUserSchema, req.body); if (!isValid) { throw new Error('参数格式错误'); } // 业务逻辑处理 return this.userService.create(req.body); }
第三步:封装校验中间件复用 Schema
如果想把校验逻辑抽离到中间件,直接传入 TypeBox Schema 即可:
import { Request, Response, NextFunction } from 'express'; import { Type, Errors } from '@sinclair/typebox'; // 通用校验中间件 export function validateSchema(schema: any) { return (req: Request, res: Response, next: NextFunction) => { const validationErrors = Errors(schema, req.body); if (validationErrors.length > 0) { return res.status(400).json({ message: '参数校验失败', errors: validationErrors.map(e => e.message) }); } next(); }; }
然后在路由中同时使用中间件和 Swagger 装饰器:
@ApiOperationPost({ path: '/users', description: '创建新用户', summary: '用户注册接口' }) @ApiRequestBody({ description: '用户注册参数', required: true, schema: SchemaToJsonSchema(CreateUserSchema) }) // 传入TypeBox Schema到校验中间件 @Post('/users', validateSchema(CreateUserSchema)) async createUser(@Req() req: Request) { // 业务逻辑处理 return this.userService.create(req.body); }
第四步:优化转换逻辑(可选)
封装一个工具函数,自动处理转换后的冗余属性,让代码更简洁:
import { TSchema, SchemaToJsonSchema } from '@sinclair/typebox'; export function toSwaggerSchema(schema: TSchema) { const jsonSchema = SchemaToJsonSchema(schema); // 移除TypeBox生成的$schema属性,兼容Swagger delete jsonSchema.$schema; return jsonSchema; }
使用时直接调用:
@ApiRequestBody({ description: '用户注册参数', required: true, schema: toSwaggerSchema(CreateUserSchema) })
注意事项
- TypeBox 的复杂类型(如
Type.Union、Type.Intersect)转换为 JSON Schema 后,swagger-express-ts 基本都能兼容,若遇到特殊情况可手动调整转换后的 Schema。 - 确保 TypeBox 和 swagger-express-ts 的版本匹配,避免因版本差异导致的解析问题。
内容的提问来源于stack exchange,提问作者Mr X
相关产品推荐
相关产品推荐

