如何使用 class-validator 向 nestjs 中的验证器约束接口注入服务?
How to inject service to validator constraint interface in nestjs using class-validator?
我正在尝试将我的用户服务注入我的验证器约束接口,但它似乎不起作用:
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 记录为空,我无法访问它的方法。
对此事有什么见解吗?
您需要更新 class-validator
的容器以使用 Nest 应用程序以允许在任何地方进行依赖注入。 This GitHub Issue 介绍了如何做到这一点以及人们面临的一些困难。
无需阅读 link 即可快速修复:
async function bootstrap() {
const app = await NestFactory.create(ApplicationModule);
useContainer(app, { fallback: true });
await app.listen(3000);
}
bootstrap();
执行此操作时,请确保您还像往常一样注册验证器 @Injectable()
对于可能遇到此问题的人:
class-validator 要求您使用服务容器,如果您想将依赖项注入自定义验证器约束 classes。来自: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 bootstrap 函数中:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
useContainer(app.select(AppModule), { fallbackOnErrors: true });
...}
{fallbackOnErrors: true} 是必需的,因为当 DI 没有要求时 Nest 会抛出异常 class。
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 {
}
顺便说一句,这在端到端测试中不起作用。这就是我得到它的方式 运行.
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
app.useGlobalPipes(GetValidationPipe());
useContainer(app.select(AppModule), { fallbackOnErrors: true });
await app.init();
});
我正在尝试将我的用户服务注入我的验证器约束接口,但它似乎不起作用:
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 记录为空,我无法访问它的方法。
对此事有什么见解吗?
您需要更新 class-validator
的容器以使用 Nest 应用程序以允许在任何地方进行依赖注入。 This GitHub Issue 介绍了如何做到这一点以及人们面临的一些困难。
无需阅读 link 即可快速修复:
async function bootstrap() {
const app = await NestFactory.create(ApplicationModule);
useContainer(app, { fallback: true });
await app.listen(3000);
}
bootstrap();
执行此操作时,请确保您还像往常一样注册验证器 @Injectable()
对于可能遇到此问题的人:
class-validator 要求您使用服务容器,如果您想将依赖项注入自定义验证器约束 classes。来自: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 bootstrap 函数中:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
useContainer(app.select(AppModule), { fallbackOnErrors: true });
...}
{fallbackOnErrors: true} 是必需的,因为当 DI 没有要求时 Nest 会抛出异常 class。
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 {
}
顺便说一句,这在端到端测试中不起作用。这就是我得到它的方式 运行.
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
app.useGlobalPipes(GetValidationPipe());
useContainer(app.select(AppModule), { fallbackOnErrors: true });
await app.init();
});