Using the In-Built NestJS ValidationPipe
Let's get to validating your data.
Join the DZone community and get the full member experience.
Join For FreeThe in-built NestJS ValidationPipe is a great way to handle validations in an application.
Validations are an extremely important aspect of any production-level application. Often, developers have to write large amounts of code to handle even basic validations. This is largely counter-productive.
With NestJS ValidationPipe, handling several validations becomes much easier. In this post, we look at how to use the in-built ValidationPipe.
So let’s begin.
1 – NestJS ValidationPipe
ValidationPipe is similar to other in-built pipes available with NestJS. In case you want to know more about the basics of NestJS Pipes, please refer to this post.
Apart from ValidationPipe, other pipes such as ParseIntPipe, ParseBoolPipe, ParseUUIDPipe can also be used for validation purposes. However, ValidationPipe makes use of the powerful class-validator package. Due to this, we can set up validations in a declarative manner.
To begin with ValidationPipe, we need to first install the class-validator package. Below is the command.
npm i --save class-validator class-transformer
You can read more about class-validator from its official site.
2 – Setting up Auto Validation
We will start by setting up auto validation using ValidationPipe.
As a first step, we bootstrap the ValidationPipe in the bootstrap function available in main.ts. See the example below :
main.tsimport { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe())
await app.listen(3000);
}
bootstrap();
Here, we call the useGlobalPipes() method. Basically, we pass it as an instance of the ValidationPipe class. Notice here that ValidationPipe is part of the @nestjs/common package.
To test our pipe, let’s create a simple controller as below.
user.controller.tsimport { Body, Controller, Post } from "@nestjs/common";
import { CreateUserModel } from "./create-user-model";
@Controller()
export class UserController {
@Post("/user")
create(@Body() createUserModel: CreateUserModel) {
console.log("New User Created");
}
}
As you can see, it is a simple controller. It basically accepts a model to create a new user. Let’s see how the model looks like.
create-user-model.tsimport { IsEmail, IsNotEmpty } from "class-validator";
export class CreateUserModel {
@IsEmail()
email: string;
@IsNotEmpty()
password: string;
}
Notice the decorators @IsEmail() and @IsNotEmpty(). These decorators basically represent the validation rules for particular fields. In other words, the email field should contain a valid email id. And the password field should not be empty. These decorators are part of the class-validator package.
For example, if an incoming request with an invalid email hits our endpoint, the response would be as below:
{
"statusCode": 400,
"message": [
"email must be an email"
],
"error": "Bad Request"
}
3 – ValidationPipe with Request Parameters
We can also use ValidationPipe with other request parameters such as a path parameter.
Check out the below controller.
@Get("/user/:id")
get(@Param() params: SearchParams) {
console.log("User fetched");
}
Here, we have a path variable id. SearchParams is simply a DTO class similar to our previous example.
import { IsNumberString } from "class-validator";
export class SearchParams {
@IsNumberString()
id: number;
}
The decorator @IsNumberString ensures that only numbers are accepted. If we call the endpoint /user/xyz, we get the following error.
{
"statusCode": 400,
"message": [
"id must be a number string"
],
"error": "Bad Request"
}
4 – Disabling Error Details in ValidationPipe
Usually, it is a good practice to make your application error messages more informative. However, for some production requirements, detailed error messages are not needed.
In such cases, we can disable the error messages. Basically, we have to tweak the configuration of the ValidationPipe object.
See the following example:
main.tsimport { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe({
disableErrorMessages: true,
}))
await app.listen(3000);
}
bootstrap();
5 – Stripping or Whitelisting Properties
We can also strip unwanted properties from incoming requests. In other words, we can whitelist certain properties.
See the following DTO class.
create-user-model.tsimport { IsEmail, IsNotEmpty } from "class-validator";
export class CreateUserModel {
@IsEmail()
email: string;
@IsNotEmpty()
password: string;
address: string;
}
Here, the address field is not annotated. Basically, we have not whitelisted this property. We want this to be stripped from the payload even if the incoming request contains the same.
To achieve that, we can simply add another configuration parameter in ValidationPipe as below:
main.tsimport { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe({
disableErrorMessages: true,
whitelist: true
}))
await app.listen(3000);
}
bootstrap();
See the whitelist: true property in the configuration object. In this case, the request will be processed and the non-whitelisted properties will be stripped off.
Alternatively, we can also make the request fail. Doing so is, again, a simple matter of configuration. See the following example.
main.tsimport { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true
}))
await app.listen(3000);
}
bootstrap();
Now, if we call the end-point with extra property, we get the below error.
{
"statusCode": 400,
"message": [
"property address should not exist",
"email must be an email"
],
"error": "Bad Request"
}
The first message is telling us to remove the address property from the input payload.
Conclusion
With this, we have a detailed view of how to use the in-built NestJS ValidationPipe.
In another post, we will look at how to transform a request payload using NestJS Mapped Types.
If you have any comments or queries, please mention them in the comment section below.
Published at DZone with permission of Saurabh Dashora. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments