如何将Zod Schema转换为NestJS Swagger的CountryDto?
如何将Zod的CountrySchema转换为NestJS Swagger可用的CountryDto
你可以通过两种方式实现需求:手动编写DTO类结合Swagger装饰器,或者借助工具自动将Zod Schema转换为Swagger兼容的DTO。
方法一:手动编写CountryDto
这种方式适合简单场景,能精准控制Swagger文档的展示细节:
- 创建
CountryDto类,导入@nestjs/swagger的@ApiProperty装饰器,为每个字段配置描述、必填状态和示例值:
import { ApiProperty } from '@nestjs/swagger'; export class CountryDto { @ApiProperty({ description: '国家名称', required: true, example: 'China', }) name: string; @ApiProperty({ description: 'ISO 两位国家代码', required: true, example: 'CN', }) iso2: string; @ApiProperty({ description: 'ISO 三位国家代码', required: true, example: 'CHN', }) iso3: string; @ApiProperty({ description: '国际电话区号', required: true, example: '+86', }) dialCode: string; @ApiProperty({ description: '国旗图片URL', required: true, example: 'https://example.com/cn-flag.png', }) flagUrl: string; }
- 为了让DTO类型和Zod Schema保持一致,可通过
z.infer获取Schema的类型并让DTO实现该类型:
import { z } from 'zod'; import { ApiProperty } from '@nestjs/swagger'; import { CountrySchema } from './path-to-your-schema'; // 从Zod Schema推导类型 type CountryType = z.infer<typeof CountrySchema>; export class CountryDto implements CountryType { @ApiProperty({ description: '国家名称', required: true, example: 'China', }) name: string; @ApiProperty({ description: 'ISO 两位国家代码', required: true, example: 'CN', }) iso2: string; // 其他字段配置同上 iso3: string; dialCode: string; flagUrl: string; }
- 在控制器中使用该DTO,并结合
ZodValidationPipe做输入校验:
import { Controller, Post, Body, UsePipes } from '@nestjs/common'; import { ZodValidationPipe } from '@nestjs/zod'; import { CountryDto } from './country.dto'; import { CountrySchema } from './country.schema'; @Controller('countries') export class CountryController { @Post() @UsePipes(new ZodValidationPipe(CountrySchema)) createCountry(@Body() countryDto: CountryDto) { // 业务逻辑实现 return countryDto; } }
方法二:自动转换(基于zod-to-openapi和@nestjs/zod)
这种方式能减少重复代码,自动同步Zod Schema和Swagger文档:
- 安装依赖:
npm install zod-to-openapi @nestjs/zod
- 扩展Zod以支持OpenAPI配置,修改你的
CountrySchema:
import { z } from 'zod'; import { extendZodWithOpenApi } from 'zod-to-openapi'; // 扩展Zod,添加openapi配置方法 extendZodWithOpenApi(z); export const CountrySchema = z .object({ name: z.string({ required_error: 'Name is required', invalid_type_error: 'Name is invalid', }).openapi({ description: '国家名称', example: 'China', }), iso2: z.string({ required_error: 'iso2 is required', invalid_type_error: 'iso2 is invalid', }).openapi({ description: 'ISO 两位国家代码', example: 'CN', }), iso3: z.string({ required_error: 'iso3 is required', invalid_type_error: 'iso3 is invalid', }).openapi({ description: 'ISO 三位国家代码', example: 'CHN', }), dialCode: z.string({ required_error: 'dialCode is required', invalid_type_error: 'dialCode is invalid', }).openapi({ description: '国际电话区号', example: '+86', }), flagUrl: z.string({ required_error: 'flagUrl is required', invalid_type_error: 'flagUrl is invalid', }).openapi({ description: '国旗图片URL', example: 'https://example.com/cn-flag.png', }), }) .required() .openapi({ title: 'CountryDto', description: '国家信息DTO', });
- 使用
@nestjs/zod的createZodDto生成兼容Swagger的DTO:
import { createZodDto } from '@nestjs/zod'; import { CountrySchema } from './country.schema'; // 自动生成DTO,同时继承Zod的校验规则 export class CountryDto extends createZodDto(CountrySchema) {}
- 在
main.ts中配置Swagger时,将该DTO加入额外模型:
import { NestFactory } from '@nestjs/core'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { AppModule } from './app.module'; import { CountryDto } from './country.dto'; async function bootstrap() { const app = await NestFactory.create(AppModule); const config = new DocumentBuilder() .setTitle('API文档') .setDescription('国家管理API') .setVersion('1.0') .build(); // 注册DTO,让Swagger识别并生成对应文档 const document = SwaggerModule.createDocument(app, config, { extraModels: [CountryDto], }); SwaggerModule.setup('api', app, document); await app.listen(3000); } bootstrap();
这样Swagger会自动读取Zod Schema中的OpenAPI配置生成接口文档,同时createZodDto生成的DTO也能直接用于控制器的参数校验。
内容的提问来源于stack exchange,提问作者Owali Ullah Shawon
相关产品推荐
相关产品推荐

