How to get request in class-validator constraint in nestjs

use*_*012 10 typescript class-validator nestjs

If I want to validate the role which user post to api to create if is unique of relation enterprise

@Injectable({ scope: Scope.REQUEST })
@ValidatorConstraint({ name: 'Ddd', async: true })
export class IsUnqiueForEnterpriseConstraint implements ValidatorConstraintInterface {
    constructor(@Inject(REQUEST) private request: Request) {}

    async validate(value: any, args: ValidationArguments) {
        const { enterprise } = this.request.user as any
        const { model } = args.constraints[0] as IParams;
        if(!enterprise) return false;
        if (!model) return false;
        const repo = getManager().getRepository(model as ObjectType<any>);
        const item = await repo.findOne({
            [args.property]: value,
            enterprise: { id: enterprise.id },
        });
        return !item;
    }

    defaultMessage(args: ValidationArguments) {
        const { model } = args.constraints[0];
        if (!model) {
            return 'Model not been specified!';
        }
        return `${args.property} of ${model.name} must been unique!`;
    }
}
export function IsUnqiueForEnterprise(params: IParams, validationOptions?: ValidationOptions) {
    return (object: Record<string, any>, propertyName: string) => {
        registerDecorator({
            target: object.constructor,
            propertyName,
            options: validationOptions,
            constraints: [params],
            validator: IsUnqiueForEnterpriseConstraint,
        });
    };
}
Run Code Online (Sandbox Code Playgroud)

And in main.ts I will container class-validator like follow

useContainer(app, { fallbackOnErrors: true });
Run Code Online (Sandbox Code Playgroud)

and dto

@IsUnqiueForEnterprise({model: Role})
label!: string;
Run Code Online (Sandbox Code Playgroud)

但受限的requestundefined,我怎样才能得到它呢?

小智 1

您应该执行多个步骤:

1-创建一个ContextInterceptor,当请求有正文时将用户信息注入到请求中(如果您有 post API,那么您的请求有正文)。

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

@Injectable()
export class ContextInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest();
    if (request.body) {
      request.body.context = {
        user: request.user,
      };
    }

    return next.handle();
  }
}
Run Code Online (Sandbox Code Playgroud)

2-在 RoleController 或全局中使用拦截器。

...
@Controller('roles')
@UseInterceptors(ContextInterceptor)
export class RolesController {

...

}
Run Code Online (Sandbox Code Playgroud)

3-创建StripContextPipe以从请求正文中剥离上下文,以在约束中使用后删除上下文。

/*
https://docs.nestjs.com/pipes
*/

import { PipeTransform, Injectable } from '@nestjs/common';

@Injectable()
export class StripContextPipe implements PipeTransform {
  transform(value: any) {
    if (value.context) {
      // drop context key in the desired way
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      const { context, ...rest } = value;
      return rest;
    }
    return value;
  }
}
Run Code Online (Sandbox Code Playgroud)

4-在 RolesController 中的 post 方法上使用管道。

  @Post()
  @UsePipes(new ValidationPipe({ whitelist: true }))
  async create(
    @Body(StripContextPipe)
    createDto: createRoleDto,
    @Res() res: Response,
  ) {
    const record = await this.roleService.create(      
      createDto,
    );
    return res.success(record);
  }
Run Code Online (Sandbox Code Playgroud)

5-创建ContextAwareDto以从中扩展createRoleDto 。

import { Allow } from 'class-validator';

export class ContextAwareDto {
  @Allow()
  context?: {
    user: any;
  };
}

export class createRoleDto extends ContextAwareDto {
...
@IsUnqiueForEnterprise({model: Role})
label!: string;
...
}
Run Code Online (Sandbox Code Playgroud)

6-在约束验证器中读取用户表单上下文

...
async validate(dto, validationArguments?: ContextValidationArguments) {
      const user = validationArguments.object.context.user;
      // you can load relations of user with find and repo
      // repo.find({where:{id:user.id},relations: {enterpris:true}})
...
Run Code Online (Sandbox Code Playgroud)