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.

  1. async function bootstrap() {
  2. const app = await NestFactory.create(ApplicationModule);
  3. app.useGlobalPipes(new ValidationPipe());
  4. await app.listen(3000);
  5. }
  6. bootstrap();

To test our pipe, let’s create a basic endpoint.

  1. @Post()
  2. create(@Body() createUserDto: CreateUserDto) {
  3. return 'This action adds a new user';
  4. }

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.

  1. import { IsEmail, IsNotEmpty } from 'class-validator';
  2. export class CreateUserDto {
  3. @IsEmail()
  4. email: string;
  5. @IsNotEmpty()
  6. password: string;
  7. }

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:

  1. {
  2. "statusCode": 400,
  3. "error": "Bad Request",
  4. "message": [
  5. {
  6. "target": {},
  7. "property": "email",
  8. "children": [],
  9. "constraints": {
  10. "isEmail": "email must be an email"
  11. }
  12. }
  13. ]
  14. }

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:

  1. @Get(':id')
  2. findOne(@Param() params: FindOneParams) {
  3. return 'This action returns a user';
  4. }

FindOneParams, like a DTO, is simply a class that defines validation rules using class-validator. It would look like this:

  1. import { IsNumberString } from 'class-validator';
  2. export class FindOneParams {
  3. @IsNumberString()
  4. id: number;
  5. }

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:

  1. app.useGlobalPipes(
  2. new ValidationPipe({
  3. disableErrorMessages: true,
  4. })
  5. );

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.

  1. app.useGlobalPipes(
  2. new ValidationPipe({
  3. whitelist: true,
  4. })
  5. );

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.

  1. app.useGlobalPipes(
  2. new ValidationPipe({
  3. transform: true,
  4. })
  5. );

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.