NestJS Payload Validation
Tags: typescript, security, nestjs, node
Published: 2022-03-02 14:43:16

While working on building APIs, we started talking about how we can validate user input and since we are using NestJS, I started looking into in-house solution for the same. So, I started going through [NestJS](https://docs.nestjs.com/) documentation, looking for a potential solution.

The NestJS documentation is very well written, and I was able to come up with a solution using [ValidationPipe](https://docs.nestjs.com/techniques/validation) in couple of days. But, to build something simple, going through the documentation becomes a bit tedious. The aim of this blog post is to help you get started (with input validation) quickly if you are trying to build something less complex or rather, you can consider this as a beginner’s guide.
> Note: 
Since this blog is not about NestJS itself, we will proceed, assuming you know how to write microservices using NestJS and what [DTOs](https://docs.nestjs.com/controllers#request-payloads) are.

---
Before we begin, here’s the link to the [github repo](https://github.com/shubham16kadam/nestjs-payload-validation.git) for the NestJS project which has the below mentioned code example for you to try locally.

Now, lets assume that we have written a microservice that handles employee details and you want to add new employee details via POST request. The request payload would look like:

```
{
   "name":"Peter Griffin",
   "age":44,
   "address":{
      "country":"US",
      "state":"California",
      "city":"Los Angeles",
      "street":"Alameda Street",
      "flatNo":12
   },
   "projects":[
      "CustomerInsights",
      "Matter"
   ],
   "workExperience":[
      {
         "orgName":"SomeFamousOrg",
         "exp":5
      },
      {
         "orgName":"SomeSuperFamousOrg",
         "exp":7
      }
   ]
}
```
DTOs for above payload would look like below:

```
export class Address {
  country: string;
  state: string;
  city: string;
  street: string;
  flatNo: number;
}

export class WorkExperience {
  orgName: string;
  exp: number;
}

export class EmployeeDetails {
  name: string;
  age: number;
  address: Address;
  projects: string[];
  workExperience: WorkExperience[];
}
```
Below are the validations we need to apply to the mentioned payload:

1. Employee `name` should only contain characters i.e. numeric values and symbols not allowed.
2. `age` should be integer value and greater than (>=) 18 and less than (<=) 65.
3. `address` has below restrictions:
    1. `country`, `state`, `street` and `city` should only consist of characters.
    2. `flatNo` should be integer
4. `projects` should be an array of string.
5. All the mentioned details must be provided i.e. empty values not allowed.
6. There should be length related restriction on string values.

To get this job done, we will use [validation decorators](https://github.com/typestack/class-validator#validation-decorators) provided by the [class-validator](https://github.com/typestack/class-validator#class-validator) package.
###### Installation command for `class-validator` package:
`~ npm install class-validator --save`
The DTOs after changes (along with the imports) would look like below:

```
import {
  ArrayNotEmpty,
  IsArray,
  IsInt,
  IsNotEmpty,
  IsString,
  Matches,
  MaxLength,
  ValidateNested,
  Min,
  Max,
  IsNumber,
} from 'class-validator';
import { Type } from 'class-transformer';

export class Address {
  @IsString()
  @IsNotEmpty()
  @Matches('^[a-zA-Z\\s]+$')
  @MaxLength(15)
  country: string;

  @IsString()
  @IsNotEmpty()
  @Matches('^[a-zA-Z\\s]+$')
  @MaxLength(15)
  state: string;

  @IsString()
  @IsNotEmpty()
  @Matches('^[a-zA-Z\\s]+$')
  @MaxLength(15)
  city: string;

  @IsString()
  @IsNotEmpty()
  @Matches('^[a-zA-Z\\s]+$')
  @MaxLength(20)
  street: string;

  @IsInt()
  @IsNotEmpty()
  flatNo: number;
}

export class WorkExperience {
  @IsString()
  @IsNotEmpty()
  @Matches('^[a-zA-Z0-9\\s]+$')
  @MaxLength(30)
  orgName: string;

  @IsNumber({ maxDecimalPlaces: 2 })
  @IsNotEmpty()
  exp: number;
}

export class EmployeeDetails {
  @IsNotEmpty()
  @IsString()
  @Matches('^[a-zA-Z\\s]+$')
  @MaxLength(50)
  name: string;

  @IsNotEmpty()
  @IsInt()
  @Min(18)
  @Max(65)
  age: number;

  @ValidateNested()
  @Type(() => Address)
  @IsNotEmpty()
  address: Address;

  @IsArray()
  @ArrayNotEmpty()
  @IsString({ each: true })
  @Matches('^[a-zA-Z0-9\\s]+$', undefined, { each: true })
  @MaxLength(30, { each: true })
  projects: string[];

  @IsArray()
  @ArrayNotEmpty()
  @ValidateNested({ each: true })
  @Type(() => WorkExperience)
  workExperience: WorkExperience[];
}
```

---

#### Explanation
The validation for input values of `name` and `age` is straightforward. Let’s look at the attributes which are a bit complex.

###### _projects:_
projects attribute is of type array i.e. array of string, so the decorators `@IsArray()` and `@ArrayNotEmpty()` were applied accordingly.

But, how do we validate values inside the array? For example, if we have an array:

`projects: [‘CustomerInsights’, ‘DemoPipeline’]`

How do we validate values ‘CustomerInsights’ and ‘DemoPipeline’ individually? How do we make sure that they satisfy all the necessary restrictions?

The answer is, by passing validation option `each: true` inside the desired decorator.

why? Because,

> If your field is an array and you want to perform validation of each item in the array you must specify a special `each: true` decorator option.
[NestJS Documentation ](https://github.com/typestack/class-validator#validating-arrays)

We want the array values to be string, so we use `@IsString()` decorator and pass argument `each: true` to it, i.e. `@IsString({ each: true })`. Similar approach is applied to other decorators like `@Matches()` and `@MaxLength()` as well.

###### _address_:
The `address` attribute is not of primitive type, but instead, is an object which consists of nested object. Due to this, we applied `@ValidateNested()` decorator along with `@Type()` decorator, to indicate object type and applied validation separately to each of its nested objects (refer class `Address`).

###### _workExperience_:
The `workExperience` is similar to the `address` attribute as far as its type is concerned, the only difference is, instead of consisting of nested objects, it represents ‘array of nested objects‘, and hence, we added the `each: true` option to the `@ValidateNested()` decorator i.e.`@ValidateNested({ each: true })` and this will ensure that all the nested objects are validated.

---

And we are done! Hope you guys enjoyed it.
In my [next blog](https://dev.to/shubham_kadam/nestjs-custom-payload-validation-3hh7), I’ll talk about how to perform custom payload validation.
> Please do checkout the project's [github repo](https://github.com/shubham16kadam/nestjs-payload-validation.git)


![Done](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lrkxfg3e8x273fejah2d.gif)

#### Stay tuned, Thank You!