如何在NestJS中自定义Param装饰器,让SwaggerUI显示正确参数
解决NestJS自定义UUID参数装饰器的Swagger动态参数名问题
问题根源
你之前的元数据工厂函数是在装饰器定义阶段执行的,而非使用阶段,因此无法获取到每个场景下传入的data参数(如eventId、ticketId),导致Swagger只能显示固定的uuid参数名。
方案一:改造自定义装饰器为组合装饰器
直接让装饰器接收参数名,同时整合Swagger的@ApiParam装饰器,动态生成对应参数的文档信息:
import { createParamDecorator, ExecutionContext, BadRequestException, applyDecorators } from '@nestjs/common'; import { ApiParam } from '@nestjs/swagger'; export const IsUUIDParam = (paramName: string) => { // 核心验证逻辑的参数装饰器 const uuidDecorator = createParamDecorator( (data: string, ctx: ExecutionContext) => { const request = ctx.switchToHttp().getRequest(); const uuid = request.params[data]; if (!uuid) return uuid; // 验证UUIDv4格式(忽略大小写) const isValidUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(uuid); if (!isValidUUID) { throw new BadRequestException(`Invalid ${data} format`); } return uuid; }, )(paramName); // 组合验证装饰器和Swagger参数文档装饰器 return applyDecorators( uuidDecorator, ApiParam({ name: paramName, in: 'path', required: true, type: 'string', format: 'uuid', // 明确标记为UUID格式,Swagger会自动识别 }), ); };
控制器使用方式
@Get(':eventId') async findOne( @UserId() userId: string, @IsUUIDParam('eventId') eventId: string, ): Promise<EventEntity> { return this.eventService.findOne(userId, eventId); } // 另一个场景示例 @Delete(':ticketId') async deleteTicket( @UserId() userId: string, @IsUUIDParam('ticketId') ticketId: string, ): Promise<void> { await this.ticketService.delete(userId, ticketId); }
方案二:改用管道+原生@Param装饰器(NestJS最佳实践)
将UUID验证逻辑抽离为独立管道,配合原生@Param和Swagger的@ApiParam,更符合Nest的分层设计:
1. 创建UUID验证管道
import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common'; @Injectable() export class UUIDValidationPipe implements PipeTransform { transform(value: string, metadata: { data: string }) { const isValidUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value); if (!isValidUUID) { throw new BadRequestException(`Invalid ${metadata.data} format`); } return value; } }
2. 控制器使用方式
import { ApiParam } from '@nestjs/swagger'; @Get(':eventId') @ApiParam({ name: 'eventId', required: true, type: 'string', format: 'uuid' }) async findOne( @UserId() userId: string, @Param('eventId', UUIDValidationPipe) eventId: string, ): Promise<EventEntity> { return this.eventService.findOne(userId, eventId); }
两种方案都能实现动态参数名的Swagger文档生成,方案一适合希望保留单一装饰器调用的场景,方案二更贴合NestJS的模块化设计思想。
内容的提问来源于stack exchange,提问作者Tibz
相关产品推荐
相关产品推荐

