How to do validation with database like unique filed validation in nest JS using the class validator?
I created a custom validation class and tried it. But userService
was undefined when I console log that service in the validate function.
import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from 'class-validator';
import { Injectable } from '@nestjs/mon';
import { UserService } from './user.service';
@ValidatorConstraint({ name: 'unique', async: true })
@Injectable()
export class UniqueFieldValidator implements ValidatorConstraintInterface {
constructor(private readonly userService: UserService) {
}
validate = async (value: any, args: ValidationArguments): Promise<boolean> => {
console.log(this.userService); // <-- This log prints undefined
const [entityClass, fieldName] = args.constraints;
const entity = await this.userService.findByFieldValue({ [fieldName]: value });
return !entity;
}
defaultMessage(args: ValidationArguments) {
const [entityClass, fieldName] = args.constraints;
return `${fieldName} must be unique`;
}
}
I have called this class in side createUserDto
Class as below.
import { IsEnum, IsNotEmpty, MinLength, Validate } from "class-validator";
import { CompanyStatuses } from "src/pany/dto/pany.enums";
import { User } from "../entities/user.entity";
import { UniqueFieldValidator } from "../unique-field-validator";
export class CreateUserDto {
@IsNotEmpty()
@MinLength(3)
@Validate(UniqueFieldValidator, [User, 'username'])
username: string
}
UniqueFieldValidator
class is calling successfully.
But because that userServices
is undefined in the validate function when I sent the request to create a user, it's returning the error message saying
TypeError: Cannot read properties of undefined (reading 'findByFieldValue')
at UniqueFieldValidator.validate
If anyone has experience this in NestJs with class-validator please help me. Thank you!
P.S.
Below code shows how i have written my userModule and i have added both UserService and Validator class to the Providers array.also have placed @injectable() decorator top of the UserService class. but it's not working still.
import { Module } from '@nestjs/mon';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
import { UniqueFieldValidator } from './unique-field-validator';
@Module({
controllers: [UserController],
providers: [UserService,UniqueFieldValidator],
imports: [TypeOrmModule.forFeature([User])],
exports: [UserService,TypeOrmModule]
})
export class UserModule { }
How to do validation with database like unique filed validation in nest JS using the class validator?
I created a custom validation class and tried it. But userService
was undefined when I console log that service in the validate function.
import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from 'class-validator';
import { Injectable } from '@nestjs/mon';
import { UserService } from './user.service';
@ValidatorConstraint({ name: 'unique', async: true })
@Injectable()
export class UniqueFieldValidator implements ValidatorConstraintInterface {
constructor(private readonly userService: UserService) {
}
validate = async (value: any, args: ValidationArguments): Promise<boolean> => {
console.log(this.userService); // <-- This log prints undefined
const [entityClass, fieldName] = args.constraints;
const entity = await this.userService.findByFieldValue({ [fieldName]: value });
return !entity;
}
defaultMessage(args: ValidationArguments) {
const [entityClass, fieldName] = args.constraints;
return `${fieldName} must be unique`;
}
}
I have called this class in side createUserDto
Class as below.
import { IsEnum, IsNotEmpty, MinLength, Validate } from "class-validator";
import { CompanyStatuses } from "src/pany/dto/pany.enums";
import { User } from "../entities/user.entity";
import { UniqueFieldValidator } from "../unique-field-validator";
export class CreateUserDto {
@IsNotEmpty()
@MinLength(3)
@Validate(UniqueFieldValidator, [User, 'username'])
username: string
}
UniqueFieldValidator
class is calling successfully.
But because that userServices
is undefined in the validate function when I sent the request to create a user, it's returning the error message saying
TypeError: Cannot read properties of undefined (reading 'findByFieldValue')
at UniqueFieldValidator.validate
If anyone has experience this in NestJs with class-validator please help me. Thank you!
P.S.
Below code shows how i have written my userModule and i have added both UserService and Validator class to the Providers array.also have placed @injectable() decorator top of the UserService class. but it's not working still.
import { Module } from '@nestjs/mon';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
import { UniqueFieldValidator } from './unique-field-validator';
@Module({
controllers: [UserController],
providers: [UserService,UniqueFieldValidator],
imports: [TypeOrmModule.forFeature([User])],
exports: [UserService,TypeOrmModule]
})
export class UserModule { }
Share
Improve this question
edited Jul 9, 2023 at 8:20
marc_s
756k184 gold badges1.4k silver badges1.5k bronze badges
asked Mar 7, 2023 at 9:51
Harshadeva Priyankara BandaraHarshadeva Priyankara Bandara
1691 silver badge7 bronze badges
3 Answers
Reset to default 3First please ignore above answers. you need to create isUnique class:
import { Injectable } from '@nestjs/mon'
import { ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator'
import { EntityManager } from 'typeorm'
@ValidatorConstraint({ name: 'IsUniqueConstraint', async: true })
@Injectable()
export class IsUnique implements ValidatorConstraintInterface {
constructor(private readonly entityManager: EntityManager) {}
async validate(value: any, args?: ValidationArguments): Promise<boolean> {
const [tableName, column] = args?.constraints as string[]
const dataExist = await this.entityManager
.getRepository(tableName)
.createQueryBuilder(tableName)
.where({ [column]: value })
.getExists()
return !dataExist
}
defaultMessage(validationArguments: ValidationArguments): string {
const field = validationArguments.property
return `${field} is already exist.`
}
}
Then you should go to AppModule and add IsUnique as provider
@Module({
imports: [ConfigModule.forRoot(), TypeOrmModule.forRoot(DATABASE_CONFIG), UsersModule],
providers: [ IsUnique],
})
export class AppModule {}
And Finally how to use it:
export class CreateUserDto {
@IsAlphanumeric()
@MinLength(3, { message: 'Username must have atleast 3 characters.' })
@Validate(IsUnique, ['users', 'username'])
username!: string
Final configuration will be this inside main.ts in bootstrap method
useContainer(app.select(AppModule), { fallbackOnErrors: true })
Yeah! I found a solution and posting it to my own question for help to someone getting this issue in the future.
Just add useContainer(app.select(AppModule), { fallbackOnErrors: true });
in your root method.
Then my main.ts
was like this.
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { useContainer } from 'class-validator';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
useContainer(app.select(AppModule), { fallbackOnErrors: true });
await app.listen(3000);
}
bootstrap();
I'm posting this to my own question to help someone in the future.
I am using Prisma and I got the same problem, to resolve it I changed my main.ts to:
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
import { ValidationPipe } from "@nestjs/mon";
import { useContainer } from "class-validator";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());
useContainer(app.select(AppModule), { fallbackOnErrors: true });
await app.listen(3000);
}
bootstrap();
This is my appModule:
import { Module } from "@nestjs/mon";
import { ConfigModule } from "@nestjs/config";
import { UserModule } from "./modules/user/user.module";
import { AuthService } from "./modules/auth/auth.service";
import { AuthController } from "./modules/auth/auth.controller";
import { JwtModule } from "@nestjs/jwt";
import { jwtConstants } from "./modules/auth/constants";
import { PrismaService } from "./database/prisma/prisma.service";
import { DatabaseModule } from "./database/database.module";
import { ValidatorsModule } from "./validators/validators.module";
@Module({
imports: [
ConfigModule.forRoot(),
UserModule,
JwtModule.register({
secret: jwtConstants.secret,
signOptions: { expiresIn: "3600s" },
}),
DatabaseModule,
ValidatorsModule,
],
controllers: [AuthController],
providers: [AuthService, PrismaService],
exports: [PrismaService],
})
export class AppModule {}
And my databaseModule:
import { Module } from "@nestjs/mon";
import { PrismaService } from "./prisma/prisma.service";
@Module({
providers: [PrismaService],
exports: [PrismaService],
})
export class DatabaseModule {}