Validation
It is best practice to validate the correctness of any data sent into a web application. To automatically validate incoming requests, Nest provides a built-in ValidationPipe
, which makes use of the powerful class-validator package and its declarative validation decorators. The ValidationPipe
provides a convenient approach to enforce validation rules for all incoming client payloads, where the specific rules are declared with simple annotations in local class/DTO declarations in each module.
Overview
In the Pipes chapter, we went through the process of building a simple validation pipe to demonstrate how the process works. Be sure to review that chapter to best understand the topics of this chapter. Here, we’ll focus on various real world use cases of the ValidationPipe
, and using some of its advanced customization features.
Auto-validation
We’ll start by binding ValidationPipe
at the application level, thus ensuring all endpoints are protected from receiving incorrect data.
async function bootstrap() {
const app = await NestFactory.create(ApplicationModule);
app.useGlobalPipes(new ValidationPipe());
await app.listen(3000);
}
bootstrap();
To test our pipe, let’s create a basic endpoint.
@Post()
create(@Body() createUserDto: CreateUserDto) {
return 'This action adds a new user';
}
Now we can add a few validation rules in our CreateUserDto
. We do this using decorators provided by the class-validator
package, described in detail here. In this fashion, any route that uses the CreateUserDto
will automatically enforce these validation rules.
import { IsEmail, IsNotEmpty } from 'class-validator';
export class CreateUserDto {
@IsEmail()
email: string;
@IsNotEmpty()
password: string;
}
With these rules in place, if a request hits our endpoint with an invalid email
property in the request body, the application will automatically respond with a 400 Bad Request
code, along with the following response body:
{
"statusCode": 400,
"error": "Bad Request",
"message": [
{
"target": {},
"property": "email",
"children": [],
"constraints": {
"isEmail": "email must be an email"
}
}
]
}
In addition to validating request bodies, the ValidationPipe
can be used with other request object properties as well. Imagine that we would like to accept :id
in the endpoint path. To ensure that only numbers are accepted for this request parameter, we can use the following construct:
@Get(':id')
findOne(@Param() params: FindOneParams) {
return 'This action returns a user';
}
FindOneParams
, like a DTO, is simply a class that defines validation rules using class-validator
. It would look like this:
import { IsNumberString } from 'class-validator';
export class FindOneParams {
@IsNumberString()
id: number;
}
Disable detailed errors
Error messages can be helpful to explain what was incorrect in a request. However, some production environments prefer to disable detailed errors. Do this by passing an options object to the ValidationPipe
:
app.useGlobalPipes(
new ValidationPipe({
disableErrorMessages: true,
})
);
As a result, detailed error messages won’t be displayed in the response body.
Stripping properties
Our ValidationPipe
can also filter out properties that should not be received by the method handler. In this case, we can whitelist the acceptable properties, and any property not included in the whitelist is automatically stripped from the resulting object. For example, if our handler expects email
and password
properties, but a request also includes an age
property, this property can be automatically removed from the resulting DTO. To enable such behavior, set whitelist
to true
.
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
})
);
When set to true, this will automatically remove non-whitelisted properties (those without any decorator in the validation class).
Alternatively, you can stop the request from processing when non-whitelisted properties are present, and return an error response to the user. To enable this, set the forbidNonWhitelisted
option property to true
, in combination with setting whitelist
to true
.
Transform payload objects
Payloads coming in over the network are plain JavaScript objects. The ValidationPipe
can automatically transform payloads to be objects typed according to their DTO classes. To enable auto-transformation, set transform
to true
.
app.useGlobalPipes(
new ValidationPipe({
transform: true,
})
);
WebSockets & Microservices
While this chapter shows examples using HTTP style applications (e.g., Express or Fastify), the ValidationPipe
works the same for WebSockets and microservices, regardless of the transport method that is used.
Learn more
Read more about custom validators, error messages, and available decorators as provided by the class-validator
package here.