【问题标题】:How to inject service to validator constraint interface in nestjs using class-validator?如何使用类验证器向nestjs中的验证器约束接口注入服务?
【发布时间】:2020-05-20 13:43:50
【问题描述】:

我正在尝试将我的用户服务注入我的验证器约束界面,但它似乎不起作用:

import { ValidatorConstraintInterface, ValidatorConstraint, ValidationArguments, registerDecorator, ValidationOptions } from "class-validator";
import { UsersService } from './users.service';

@ValidatorConstraint({ async: true })
export class IsEmailAlreadyInUseConstraint implements ValidatorConstraintInterface {
    constructor(private usersService: UsersService) {
        console.log(this.usersService);
    }
    validate(email: any, args: ValidationArguments) {
        return this.usersService.findUserByEmail(email).then(user => {
             if (user) return false;
             return true;
        });
        return false;
    }

}

但是,由于 usersService 被记录为 null,我无法访问它的方法。

对这个问题有任何见解吗?

【问题讨论】:

    标签: typescript nestjs class-validator


    【解决方案1】:

    对于可能遇到此问题的人:

    如果您想将依赖项注入自定义验证器约束类,则类验证器要求您使用服务容器。来自:https://github.com/typestack/class-validator#using-service-container

    import {useContainer, Validator} from "class-validator";
    
    // do this somewhere in the global application level:
    useContainer(Container);
    

    这样我们就需要将用户容器功能添加到全局应用层。

    1.应用声明后将以下代码添加到您的 main.ts 引导函数:

    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
      useContainer(app.select(AppModule), { fallbackOnErrors: true });
    ...}
    

    {fallbackOnErrors: true} 是必需的,因为当 DI 没有所需的类时 Nest 会抛出异常。

    2。将 Injectable() 添加到您的约束中:

    import {ValidatorConstraint, ValidatorConstraintInterface} from 'class-validator';
    import {UsersService} from './user.service';
    import {Injectable} from '@nestjs/common';
    
    @ValidatorConstraint({ name: 'isUserAlreadyExist', async: true })
    @Injectable() // this is needed in order to the class be injected into the module
    export class IsUserAlreadyExist implements ValidatorConstraintInterface {
        constructor(protected readonly usersService: UsersService) {}
    
        async validate(text: string) {
            const user = await this.usersService.findOne({
                email: text
            });
            return !user;
        }
    }
    

    3.将约束作为提供者注入到您的模块中,并确保您打算注入到约束中的服务也可用于模块级别:

    import {Module} from '@nestjs/common';
    import { UsersController } from './user.controller';
    import { UsersService } from './user.service';
    import { IsUserAlreadyExist } from './user.validator';
    
    @Module({
        controllers: [UsersController],
        providers: [IsUserAlreadyExist, UsersService],
        imports: [],
        exports: []
    })
    export class UserModule {
    }
    

    【讨论】:

    • 这是一个很好的答案,但是,我很想看看如何将容器注入 app.module.ts 而不是 main.ts,因为在运行测试时 main.ts 不会被触发.
    • 我无法弄清楚第 3 步 - 你的回答让我省了很多心 :)
    • @FooBar 你可以将 ModuleRef 注入到模块中(constructor(private moduleRef: ModuleRef) {}) 然后在 onModuleInit(onModuleInit() { useContainer(this.moduleRef, { fallbackOnErrors: true }); }) 中调用 useContainer
    【解决方案2】:

    您需要更新class-validator 的容器以使用Nest 应用程序以允许在任何地方进行依赖注入。 This GitHub Issue 讲述了如何做到这一点以及人们面临的一些困难。

    无需阅读链接即可快速修复:

    async function bootstrap() {
      const app = await NestFactory.create(ApplicationModule);
      useContainer(app, { fallback: true });
      await app.listen(3000);
    }
    bootstrap();
    

    执行此操作时,请确保您也像往常一样注册验证器 @Injectable()

    【讨论】:

      猜你喜欢
      • 2021-12-10
      • 1970-01-01
      • 2022-08-02
      • 1970-01-01
      • 2022-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多