### Title: Custom Validation with Database in NestJS
### Description:
This article delves into the implementation of custom validation logic within a NestJS application, specifically focusing on integrating database constraints to ensure data integrity and security. It covers how to create custom decorators for validation, utilize database constraints, and integrate these validations seamlessly into the application.
### Content:
In modern web applications, ensuring data integrity is crucial. NestJS, an open-source framework for building efficient server-side applications using TypeScript, offers robust tools for validation. However, sometimes out-of-the-box validators may not meet all our needs, especially when dealing with complex business rules that need to be enforced against a database. This article will guide you through the process of creating custom validation decorators in NestJS and integrating them with database constraints to ensure data integrity and security.
#### Step 1: Setting Up Your NestJS Project
First, let's set up a new NestJS project if you haven't already. You can use the following command to initialize a new NestJS project:
```bash
npm init nest new my-nest-app
```
Then, install necessary packages like `typeorm` for database operations:
```bash
npm install typeorm @nestjs/typeorm
```
#### Step 2: Creating a User Entity
Next, we'll define a user entity using TypeORM. Create a file named `users.entity.ts` under the `src/app/users` directory:
```typescript
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ unique: true })
email: string;
@Column()
password: string;
}
```
Ensure your `app.module.ts` imports the `User` entity:
```typescript
import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './users/users.entity';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'password',
database: 'nestjs_db',
entities: [User],
synchronize: true,
}),
UsersModule,
],
})
export class AppModule {}
```
#### Step 3: Implementing Custom Validation Decorators
Custom validation decorators allow us to define our own rules and constraints. We can use decorators like `IsEmail`, `IsStrongPassword`, etc., provided by `class-validator` library or create our own.
Install the required packages:
```bash
npm install class-validator class-validator-decorators
```
Now, let's create a decorator for checking if the email exists in the database:
```typescript
import { IsNotEmpty, IsString } from 'class-validator';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
export const IsEmailUnique = () => {
return function (target: any, propertyName: string) {
const repository = Reflect.getMetadata('repository', target.constructor);
const UserRepository = repository as Repository<User>;
Object.defineProperty(target, propertyName, {
...Reflect.getOwnPropertyDescriptor(target, propertyName),
get() {
const value = this[propertyName];
if (!value) {
return value;
}
return UserRepository.findOneBy({ email: value }).then(user => {
if (user) {
throw new Error('Email already exists');
}
return value;
});
},
set(value) {
if (value) {
UserRepository.findOneBy({ email: value }).then(user => {
if (user) {
throw new Error('Email already exists');
}
});
}
this[propertyName] = value;
},
});
};
};
```
Decorate the `email` property in your `User` entity:
```typescript
import { IsEmailUnique } from './decorators/is-email-unique.decorator';
import { Column, Entity } from 'typeorm';
@Entity()
export class User {
@IsEmailUnique()
@IsNotEmpty()
@IsString()
@Column()
email: string;
// Other properties...
}
```
#### Step 4: Running the Application
Finally, start your NestJS application:
```bash
npm run start
```
With this setup, every time you try to save a new user with an email that already exists in the database, it will throw an error, ensuring data integrity.
#### Conclusion
Custom validation with database integration in NestJS provides a powerful way to enforce business rules and ensure data consistency. By leveraging decorators and TypeORM, you can easily extend the validation capabilities to include complex checks against your database. This approach not only improves the quality of your application but also makes your codebase more maintainable and secure.