Data validation in NestJS using “Pipe”

Data validation in NestJS using “Pipe”

Introduction to Nest.js “Pipe”

Pipes in NestJS are special components used to transform and validate data before it reaches the controller or controller methods. Pipes are useful when we want to ensure that the data we receive in API requests meets certain conditions or is transformed in a specific way.

Nest.js comes with built-in pipes that can be used to transform and validate data. Built-in pipes provide fast and efficient solutions for basic tasks such as validation and transformation. Here are some built-in pipes:

  • ValidationPipe: Automatic data validation using decorators.
  • ParseIntPipe: Automatic string to number conversion.
  • ParseBoolPipe: Automatic string to boolean conversion.
  • ParseArrayPipe: Automatic string to array conversion.
  • ParseUUIDPipe: Automatic UUID format validation.
  • DefaultValuePipe: Setting the default value if no value is defined.

However, if your requirements are specific, you can create “custom pipes” using the “PipeTransform” interface.

pipes

ValidationPipe

If “ValidationPipe” is used for DTO validation then we need to install additional libraries (with other built-in pipes this is not necessary). These are the two necessary libraries:

  • class-validator: Enables defining and checking validation rules.
  • class-transformer: Transforms input data into instances of DTO classes.

Use the following command to install:

What is a “class-transformer”?

“class-transformer” is a TypeScript library that enables the conversion (transformation) of plain JavaScript objects into class instances and vice versa. These are usually simple JavaScript objects (obtained, for example, from JSON) into instances of defined classes. It also allows adding logic for custom transformations and working with nested object structures.

Example: JS object to class instance

Example: class into plain JS object

What is “class-validator”?

“class-validator” is a TypeScript library that allows defining and checking validation rules for JavaScript objects. This library uses decorators to define validation rules, such as type checking, length, minimum and maximum values, required fields, regular expressions and many other rules.

These are the most commonly used:

  • @IsString(): Checks if the value is a string.
  • @IsInt(): Checks if the value is an integer.
  • @IsBoolean(): Checks if the value is boolean.
  • @IsEmail(): Checks if the value is a valid email address.
  • @IsNotEmpty(): Checks if the value is empty.
  • @MinLength(): Checks the minimum length of a string.
  • @MaxLength(): Checks the maximum length of a string.
  • @Min(): Checks the minimum value of a number.
  • @Max(): Checks the maximum value of a number.
  • @Matches(): Checks if a value matches a regular expression.

You can find a list of all decorators at this link.

Example

ValidationPipe options

The Validation Pipe in NestJS has several useful options for customizing the validation behavior. These options provide more granular control over how validation will be performed and help handle unnecessary or invalid data. The main options you can use with Validation Pipe are explained below.

a) Whitelist option

The whitelist option is used to automatically remove all properties that are not defined in the DTO (Data Transfer Object) class. When this option is enabled, any additional data not explicitly defined in the DTO class will be ignored, ensuring that only the desired properties are processed.

Example:

b) Option forbidNonWhitelisted

The option forbidNonWhitelisted works in combination with whitelist. When enabled, this option throws an error whenever a field that is not defined in the DTO class occurs, instead of just ignoring it. This is useful if you want to strictly control the data and prevent passing any additional information that does not belong to the required structure.

Example:

c) Transform option

The transform option enables automatic conversion of input data into instances of DTO classes. When enabled, input data will automatically be transformed into an instance of the DTO class, allowing easier access to methods and types within the object.

Example:

ValidatePipe at parameter level

ValidationPipe can be applied to an individual route parameter to validate input data.

If the user sends a request with an invalid id (eg not a UUID), the API returns an error:

ValidatePipe at method level

The @UsePipes decorator is used to implement ValidationPipe at the controller method level.

Valid request:

Invalid request:

The API responds with an error:

ValidatePipe at the class level

The @UsePipes decorator can be applied to a controller class, making ValidationPipe apply to all methods within that class.

Advantage: All requests within the controller are automatically validated, which reduces the need for individual declarations.

ValidatePipe globally

ValidationPipe can be registered as a global Pipe, thus applying it to all routes in the application.

Options for ValidationPipe:

  • whitelist: true – Automatically removes properties that are not defined in the DTO class.
  • forbidNonWhitelisted: true – Throws an error if unknown properties occur.
  • transform: true – Transforms input data into instances of DTO classes.

Advantage: Validation is applied automatically to all requests, without the need to declare it in each controller.

Custom pipes

If your requirements are specific, then it is not necessary to create “custom pipes”. To create pipes, you need:

  1. You create a new class that implements the PipeTransform interface.
  2. You implement the transform() method, which receives two parameters:
    • value: The input value coming from the request.
    • metadata: Value information (optionally contains type and decorator data).

Example 1: Pipes for number validation

We create a Pipe that checks if the input string is a valid number. If not, it throws an error.

Usage in controller:

If the client sends a request to /users/123, the value 123 is successfully converted to a number.

If it sends /users/abc, the API throws an error:

Example 2: Pipes for allowed values

Pipe checks if the value is from the list of allowed values.

Usage in controller:

Valid claim: /products?type=electronics

Invalid request: /products?type=clothing

Example 3: Pipes for transformation to large text

Pipe transforms the string to uppercase.

Usage in controller:

Input: {“text”: “hello world”}

Output: Message: HELLO WORLD