For those who might be suffering from this issue:
class-validator requires you to use service containers if you want to inject dependencies into your custom validator constraint classes. From: 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);
So that we need to add the user container function into the global application level.
1. Add the following code to your main.ts bootstrap function after app declaration:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
useContainer(app.select(AppModule), { fallbackOnErrors: true });
...}
The {fallbackOnErrors: true} is required, because Nest throw Exception when DI doesn't have required class.
2. Add Injectable() to your constraint:
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. Inject the constraint into your module as a provider and make sure that the service you intend to inject into your constraint are also available to a module level:
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 {
}