NestJS:如何在自定义验证器中访问 Body 和 Param?

2024-01-16

我有一个场景,我需要来自两个值的值param and body执行自定义验证。例如,我有一条路线/:photoId/tag为照片添加标签。

然而,在向照片添加标签之前,它必须验证是否已经存在与照片同名的标签。

我的控制器中有以下路线:

@Post(':photoId/tag')
@UsePipes(new ValidationPipe())
async addTag(
    @Param() params: AddTagParams,
    @Body() addTagDto: AddTagDto
) {
    // ...
}

自从:photoId提供为paramtag中提供了body的请求,它们无法在自定义验证器中相互访问,并且我无法使用这两条信息来对数据库进行检查:

export class IsPhotoTagExistValidator implements ValidatorConstraintInterface {

    async validate(val: any, args: ValidationArguments) {
        // supposed to check whether a tag of the same name already exists on photo
        // val only has the value of photoId but not the name of the tag from AddTagDto in Body
    }
}   


export class AddTagParams{
   @IsInt()
   @Validate(IsPhotoTagExistValidator)   // this doesn't work because IsPhotoTagExistValidator can't access tag in AddTagDto
   photoId: number
}

export class AddTagDto{
   @IsString()
   tag: string
}

如上例所示,val in IsPhotoTagExistValidator仅仅是photoId。但我需要两者photoId在参数和tag主体中的名称来检查特定的photoId已经有了tag.

我应该如何访问自定义验证器函数中的 Body 和 Param?如果不是,我应该如何解决这个问题?


到目前为止我找到的唯一解决方案来自此评论https://github.com/nestjs/nest/issues/528#issuecomment-497020970 https://github.com/nestjs/nest/issues/528#issuecomment-497020970

context.interceptor.ts

import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common'
import { Observable } from 'rxjs'

/**
 * Injects request data into the context, so that the ValidationPipe can use it.
 */
@Injectable()
export class ContextInterceptor implements NestInterceptor {
  intercept(
    context: ExecutionContext,
    next: CallHandler
  ): Observable<any> {
    const request = context.switchToHttp().getRequest();

    request.body.context = {
      params: request.params,
      query: request.query,
      user: request.user,
    };

    return next.handle()
  }
}

main.ts

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalInterceptors(new ContextInterceptor());
  // ...
}

如果你使用{whitelist: true} in ValidationPipe您需要允许的参数context在您的 Dto 对象中。

这可以通过扩展这样的 Dto 来完成:

context-aware.dto.ts

import { Allow } from 'class-validator';

export class ContextAwareDto {
  @Allow()
  context?: {
    params: any,
    query: any,
    user: any,
  }
}

之后,您将能够在自定义验证器中验证正文时访问请求数据validationArguments.object.context

您可以轻松调整上述内容以在验证参数或查询时访问上下文,尽管我发现仅在正文验证期间使用此内容就足够了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

NestJS:如何在自定义验证器中访问 Body 和 Param? 的相关文章

随机推荐