You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 16:47:07