<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shubham Kadam</title>
    <description>The latest articles on DEV Community by Shubham Kadam (@shubham_kadam).</description>
    <link>https://dev.to/shubham_kadam</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F336149%2F1d108ec1-0be3-4a3a-b47a-39a875e7d22d.jpeg</url>
      <title>DEV Community: Shubham Kadam</title>
      <link>https://dev.to/shubham_kadam</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shubham_kadam"/>
    <language>en</language>
    <item>
      <title>NestJS: Mocking Databases for Efficient Tests</title>
      <dc:creator>Shubham Kadam</dc:creator>
      <pubDate>Sat, 04 Nov 2023 11:02:26 +0000</pubDate>
      <link>https://dev.to/shubham_kadam/nestjs-mocking-databases-for-efficient-tests-3efl</link>
      <guid>https://dev.to/shubham_kadam/nestjs-mocking-databases-for-efficient-tests-3efl</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In NestJS, a popular Node.js framework, unit testing plays a crucial role in maintaining the reliability and quality of your codebase.&lt;/p&gt;

&lt;p&gt;One common challenge when writing unit tests for NestJS applications is dealing with database interactions, particularly when using TypeORM as the Object-Relational Mapping (ORM) library or Mongoose module for MongoDB. It's essential to isolate your tests from the actual database to make them fast, reliable, and independent of external dependencies.&lt;/p&gt;

&lt;p&gt;To address this challenge, you need to mock database calls in your unit tests. This involves simulating database interactions without actually hitting the database. By doing so, you can control the data used in your tests, improve test performance, and ensure that your tests remain consistent, even if the database schema or content changes.&lt;/p&gt;

&lt;p&gt;In our upcoming blog post, we will explore the techniques and best practices for effectively mocking Mongoose database calls in NestJS unit tests, enabling you to write tests that are efficient, maintainable, and dependable.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Prerequisite&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since our primary focus here is to talk about unit tests and database mocking, this post will assume that you have a &lt;a href="https://docs.nestjs.com/first-steps#setup"&gt;NestJS project setup&lt;/a&gt; ready, with one or more endpoints communicating with underlying &lt;a href="https://docs.nestjs.com/techniques/mongodb"&gt;Mongo database&lt;/a&gt; (or it could be any other SQL/NoSQL db).&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Lets get started&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Consider we have an Order management system, so it would naturally have an orders module which handles orders. In NestJS, orders controller will create api endpoints to allow users to perform db operations.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;orders.controler.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  Controller,
  Get,
  UseFilters,
  UseInterceptors,
  Post,
  Patch,
  Delete,
  Body,
  Param,
  Query,
  ParseIntPipe,
  DefaultValuePipe,
} from '@nestjs/common';
import {ApiBearerAuth, ApiQuery, ApiTags} from '@nestjs/swagger';
import {OrdersService} from './orders.service';
import {Order} from './schemas/order.schema';
import {CreateOrderDto} from './dto/create-order.dto';
import {UpdateOrderDto} from './dto/update-order.dto';

@ApiBearerAuth()
@ApiTags('orders')
@Controller('orders')
export class OrdersController {
  constructor(private readonly ordersService: OrdersService) {}

  /**
   * /POST endpoint
   * Used to add new order info
   * @param {CreateOrderDto} createOrderDto
   */
  @Post()
  async create(@Body() createOrderDto: CreateOrderDto): Promise&amp;lt;Order&amp;gt; {
    return await this.ordersService.create(createOrderDto);
  }

  /**
   * /GET endpoint
   * Used to get all orders data
   */
  @Get('all')
  async findAll(): Promise&amp;lt;{data: Orders[]}&amp;gt; {
    return await this.ordersService.findAll();
  }

  /**
   * /GET endpoint
   * Used to get order data by id
   * @param {string} id
   */
  @Get(':id')
  async findOne(@Param('id') id: string): Promise&amp;lt;Order&amp;gt; {
    return await this.ordersService.findOne(id);
  }

  /**
   * /PATCH endpoint
   * Used to update order info
   * @param {string} id
   */
  @Patch(':id')
  async update(@Param('id') id: string, @Body() updateOrderDto: UpdateOrderDto): Promise&amp;lt;Order&amp;gt; {
    return await this.ordersService.update(id, updateOrderDto);
  }

  /**
   * /DELETE endpoint
   * Used to delete order
   * @param {string} id
   */
  @Delete(':id')
  async delete(@Param('id') id: string): Promise&amp;lt;Order&amp;gt; {
    return await this.ordersService.delete(id);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since controller does not have any databse calls, writing unit test for it is straight forward.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;orders.controller.spec.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {Test, TestingModule} from '@nestjs/testing';
import {LoggerModule} from 'nestjs-pino';
import {OrdersController} from './orders.controller';
import {OrdersService} from './orders.service';
import {mockOrder, mockId} from '../utils/test-utils';

const mockId = '123';
const mockOrder: CreateOrderDto = {
  // ...fake order values
}

const mockOrderService = {
  create: jest.fn().mockReturnValue(mockOrder),
  findAll: jest.fn().mockReturnValue([mockOrder]),
  findOne: jest.fn().mockReturnValue(mockOrder),
  update: jest.fn().mockReturnValue(mockOrder),
  delete: jest.fn().mockReturnValue(mockOrder),
};
describe('OrderController', () =&amp;gt; {
  let controller: OrdersController;
  let service: OrdersService;

  beforeEach(async () =&amp;gt; {
    const module: TestingModule = await Test.createTestingModule({
      imports: [LoggerModule.forRoot()],
      controllers: [OrdersController],
      providers: [
        {
          provide: OrdersService,
          useValue: mockOrderService,
        },
      ],
    }).compile();

    controller = module.get&amp;lt;OrdersController&amp;gt;(OrdersController);
    service = module.get&amp;lt;OrdersService&amp;gt;(OrdersService);
  });

  afterEach(() =&amp;gt; {
    jest.clearAllMocks();
  });

  it('should be defined', () =&amp;gt; {
    expect(controller).toBeDefined();
  });

  it('should create order data', async () =&amp;gt; {
    const expectedOutput = await controller.create(mockOrder);
    expect(service.create).toHaveBeenCalledTimes(1);
    expect(service.create).toHaveBeenCalledWith(mockOrder);
    expect(expectedOutput).toEqual(mockOrder);
  });

  it('should find all order data', async () =&amp;gt; {
    const expectedOutput = await controller.findAll();
    expect(service.findAll).toHaveBeenCalledTimes(1);
    expect(expectedOutput).toEqual([mockOrder]);
  });

  it('should find order data by id', async () =&amp;gt; {
    const expectedOutput = await controller.findOne(mockId);
    expect(service.findOne).toHaveBeenCalledTimes(1);
    expect(service.findOne).toHaveBeenCalledWith(mockId);
    expect(expectedOutput).toEqual(mockOrder);
  });

  it('should update order data by id and payload', async () =&amp;gt; {
    const expectedOutput = await controller.update(mockId, mockOrder);
    expect(service.update).toHaveBeenCalledTimes(1);
    expect(service.update).toHaveBeenCalledWith(mockId, mockOrder);
    expect(expectedOutput).toEqual(mockOrder);
  });

  it('should delete order data by id', async () =&amp;gt; {
    const expectedOutput = await controller.delete(mockId);
    expect(service.delete).toHaveBeenCalledTimes(1);
    expect(service.delete).toHaveBeenCalledWith(mockId);
    expect(expectedOutput).toEqual(mockOrder);
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Order module's service file is responsible for handling business logic, which also means managing calls to mongo database.&lt;/p&gt;

&lt;p&gt;From the &lt;a href="https://docs.nestjs.com/techniques/mongodb#model-injection"&gt;documentation&lt;/a&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Model injection&lt;/strong&gt;&lt;br&gt;
With Mongoose, everything is derived from a Schema. Each schema maps to a MongoDB collection and defines the shape of the documents within that collection. Schemas are used to define Models. Models are responsible for creating and reading documents from the underlying MongoDB database.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Below, we have an &lt;code&gt;Order&lt;/code&gt; schema and we are going to define a &lt;em&gt;model&lt;/em&gt; using this schema. This model is responsible for performing read/write operations in MongoDB.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;orders.service.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {Injectable, NotFoundException} from '@nestjs/common';
import {InjectModel} from '@nestjs/mongoose';
import {Model} from 'mongoose';
import {Order, OrderDocument} from './schemas/order.schema';
import {CreateOrderDto} from './dto/create-order.dto';
import {UpdateOrderDto} from './dto/update-order.dto';
import {IOrders} from '../interface/data-interface/orders.interface';

// fields to exclude in api response
export const EXCLUDE_FIELDS = '-_id -__v';

@Injectable()
export class OrdersService {
  constructor(@InjectModel(Order.name) private orderModel: Model&amp;lt;OrderDocument&amp;gt;) {}

  async create(createOrderDto: CreateOrderDto): Promise&amp;lt;Order&amp;gt; {
    const order = await this.orderModel.create(createOrderDto);
    return order;
  }

  async findAll(): Promise&amp;lt;IOrders&amp;gt; {
    const data = await this.orderModel.find().select(EXCLUDE_FIELDS).exec();
    return {data};
  }

  async findOne(orderId: string): Promise&amp;lt;Order&amp;gt; {
    const doc = await this.orderModel.findOne({orderId}).select(EXCLUDE_FIELDS).exec();
    if (!doc) throw new NotFoundException(`Order with id '${orderId}' not found!`);
    return doc;
  }

  async update(orderId: string, updateOrderDto: UpdateOrderDto): Promise&amp;lt;Order&amp;gt; {
    const doc = await this.orderModel.findOne({orderId}).exec();

    if (!doc) throw new NotFoundException(`Failed to update order! Order with id '${orderId}' not found.`);

    Object.assign(doc, updateOrderDto);
    const order = await doc.save();
    return order;
  }

  async delete(orderId: string): Promise&amp;lt;Order&amp;gt; {
    const doc = await this.orderModel.findOneAndDelete({orderId}).select(EXCLUDE_FIELDS).exec();
    if (!doc) throw new NotFoundException(`Failed to delete order! Order with id '${orderId}' not found.`);
    return doc;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Like I said before, we have defined a Mongoose Model &lt;code&gt;orderModel&lt;/code&gt; which performs db operations and &lt;u&gt;this is the model we are going to mock while writing unit test&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;Here's how you would mock this model with all the necessary methods&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MockedOrderModel {
  constructor(private _: any) {}
  new = jest.fn().mockResolvedValue({});
  static save = jest.fn().mockResolvedValue(mockOrder);
  static find = jest.fn().mockReturnThis();
  static create = jest.fn().mockReturnValue(mockOrder);
  static findOneAndDelete = jest.fn().mockImplementation((id: string) =&amp;gt; {
    if (id == mockIdError) throw new NotFoundException();
    return this;
  });
  static exec = jest.fn().mockReturnValue(mockOrder);
  static select = jest.fn().mockReturnThis();
  static findOne = jest.fn().mockImplementation((id: string) =&amp;gt; {
    if (id == mockIdError) throw new NotFoundException();
    return this;
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And since we are mocking the DB methods, when a &lt;code&gt;save&lt;/code&gt; method gets called, &lt;code&gt;save&lt;/code&gt; method from &lt;code&gt;MockedOrderModel&lt;/code&gt; would be invoked. We have also added few more conditions while mocking these methods to invoke erroneous conditions and have better test coverage.&lt;/p&gt;

&lt;p&gt;We need to pass &lt;code&gt;MockedOrderModel&lt;/code&gt; in &lt;code&gt;Test.createTestingModule&lt;/code&gt; as a &lt;em&gt;provider&lt;/em&gt; and we are all set.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Refer &lt;a href="https://docs.nestjs.com/fundamentals/testing"&gt;NestJS testing doc&lt;/a&gt; for more info on &lt;code&gt;Test&lt;/code&gt; module&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's the unit test file&lt;br&gt;
&lt;code&gt;orders.service.spec.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {Test, TestingModule} from '@nestjs/testing';
import {getModelToken} from '@nestjs/mongoose';
import {HttpStatus, NotFoundException} from '@nestjs/common';
import {OrdersService} from './orders.service';
import {Order} from './schemas/order.schema';

const mockOrder = {} as Order;
const mockAllOrder = {data: []};
const mockId = '123';
const mockIdError = 'error';
export const EXCLUDE_FIELDS = '-_id -__v';

class MockedOrderModel {
  constructor(private _: any) {}
  new = jest.fn().mockResolvedValue({});
  static save = jest.fn().mockResolvedValue(mockOrder);
  static find = jest.fn().mockReturnThis();
  static create = jest.fn().mockReturnValue(mockOrder);
  static findOneAndDelete = jest.fn().mockImplementation((id: string) =&amp;gt; {
    if (id == mockIdError) throw new NotFoundException();
    return this;
  });
  static exec = jest.fn().mockReturnValue(mockOrder);
  static select = jest.fn().mockReturnThis();
  static findOne = jest.fn().mockImplementation((id: string) =&amp;gt; {
    if (id == mockIdError) throw new NotFoundException();
    return this;
  });
}
describe('OrdersService', () =&amp;gt; {
  let service: OrdersService;

  beforeEach(async () =&amp;gt; {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        OrdersService,
        {
          provide: getModelToken(Order.name),
          useValue: MockedOrderModel,
        },
      ],
    }).compile();

    service = module.get&amp;lt;OrdersService&amp;gt;(OrdersService);
  });

  afterEach(() =&amp;gt; {
    jest.clearAllMocks();
  });

  it('should be defined', () =&amp;gt; {
    expect(service).toBeDefined();
  });

  it('should create new order', async () =&amp;gt; {
    const expectedOutput = await service.create(mockOrder);
    expect(MockedOrderModel.create).toHaveBeenCalledTimes(1);
    expect(expectedOutput).toEqual(mockOrder);
  });

  it('should find all orders', async () =&amp;gt; {
    const expectedOutput = await service.findAll();
    expect(MockedOrderModel.find).toHaveBeenCalledTimes(1);
    expect(MockedOrderModel.exec).toHaveBeenCalledTimes(1);
    expect(MockedOrderModel.save).toHaveBeenCalledTimes(1);
    expect(MockedOrderModel.save).toBeCalledWith(EXCLUDE_FIELDS);
    expect(expectedOutput).toEqual(mockAllOrder);
  });

  describe('Get Order', () =&amp;gt; {
    it('should find order by id', async () =&amp;gt; {
      const expectedOutput = await service.findOne(mockId);
      expect(MockedOrderModel.findOne).toHaveBeenCalledTimes(1);
      expect(MockedOrderModel.findOne).toBeCalledWith(mockId);
      expect(MockedOrderModel.exec).toHaveBeenCalledTimes(1);
      expect(MockedOrderModel.save).toHaveBeenCalledTimes(1);
      expect(MockedOrderModel.save).toBeCalledWith(EXCLUDE_FIELDS);
      expect(expectedOutput).toEqual(mockOrder);
    });

    it('should throw NotFoundException', async () =&amp;gt; {
      try {
        await service.findOne(mockIdError);
      } catch (error: any) {
        expect(error.message).toEqual('Not Found');
        expect(error.status).toEqual(HttpStatus.NOT_FOUND);
        expect(error.name).toEqual('NotFoundException');
      }
    });
  });
  // ... unit test for update and delete functionality will have similar implementation
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Unit testing is a vital part of NestJS development. Mocking database calls is key to making your tests fast, reliable, and independent of external dependencies. Whether you're using TypeORM or Mongoose for MongoDB, the techniques shared in this post help you write efficient, maintainable, and dependable unit tests. By mastering database mocking, you're enhancing the quality and resilience of your NestJS applications. Happy testing!&lt;/p&gt;

</description>
      <category>unittest</category>
      <category>jest</category>
      <category>nestjs</category>
      <category>mock</category>
    </item>
    <item>
      <title>NestJS Custom Payload Validation</title>
      <dc:creator>Shubham Kadam</dc:creator>
      <pubDate>Tue, 15 Mar 2022 08:52:57 +0000</pubDate>
      <link>https://dev.to/shubham_kadam/nestjs-custom-payload-validation-3hh7</link>
      <guid>https://dev.to/shubham_kadam/nestjs-custom-payload-validation-3hh7</guid>
      <description>&lt;p&gt;This is a follow-up post to my previous blog &lt;a href="https://dev.to/shubham_kadam/nestjs-payload-validation-anf"&gt;NestJS Payload Validation&lt;/a&gt;. In this blog-post I’ll talk about how we can implement our own custom payload validation. That is, there might be a scenario where you would like to add your own logic to validate particular payload value and the class-validator package provides us with this ability.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Before we begin, here's the &lt;a href="https://github.com/shubham16kadam/nestjs-payload-validation/tree/custom-payload-validator" rel="noopener noreferrer"&gt;github repo&lt;/a&gt; for the project &lt;br&gt;
 which has below mentioned code examples.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In order to perform custom payload validation we need to implement &lt;code&gt;ValidatorConstraintInterface&lt;/code&gt; interface and its &lt;code&gt;validate&lt;/code&gt; method and post implementing the interface we need to apply &lt;code&gt;@ValidatorConstraint&lt;/code&gt; decorator to the class (which implements the interface). For instance, lets say we have deployed an api which expects payload with employee’s age information, here’s an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "age": 24
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the DTO for the same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export class EmployeeAgeDetails {
  age: number;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;age&lt;/code&gt; property needs to have some restriction, like for instance, age should be an integer value and should be greater than (&amp;gt;=) 18 and less than (&amp;lt;=) 65.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I know in real world we would expect much more info than just employee’s age, but lets keep things simple so we understand better and quicker!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Fyi, we can perform the above mention validation directly with &lt;a href="https://github.com/typestack/class-validator#validation-decorators" rel="noopener noreferrer"&gt;validation decorators&lt;/a&gt; provided by the &lt;a href="https://github.com/typestack/class-validator#class-validator" rel="noopener noreferrer"&gt;class-validator&lt;/a&gt; as well. Please checkout my &lt;a href="https://dev.to/shubham_kadam/nestjs-payload-validation-anf"&gt;NestJS Payload Validation&lt;/a&gt; blog for example.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Lets see some code examples to demonstrate above case:&lt;/p&gt;

&lt;p&gt;The class which implements &lt;code&gt;ValidatorConstraintInterface&lt;/code&gt; interface, lets call it &lt;code&gt;CustomAgeLimitValidator&lt;/code&gt;, here’s code for the same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  ValidatorConstraint,
  ValidatorConstraintInterface,
} from 'class-validator';

@ValidatorConstraint({ name: 'CustomAgeLimitValidator', async: false })
export class CustomAgeLimitValidator implements ValidatorConstraintInterface {
  validate(value: any): boolean {
    // Add validation logic here
    if (value &amp;lt; 18 || value &amp;gt; 65) return false;
    return true;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;name&lt;/code&gt; argument in &lt;code&gt;@ValidatorConstraint&lt;/code&gt; decorator represents the ‘error type’ and if not provided, the value will be generated automatically. The validation can also be asynchronous, hence the param &lt;code&gt;async&lt;/code&gt; is used in decorator &lt;code&gt;@ValidatorConstraint&lt;/code&gt; (please checkout the &lt;a href="https://www.npmjs.com/package/class-validator#custom-validation-classes" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; for more info).&lt;/p&gt;

&lt;p&gt;Here’s how you apply the &lt;code&gt;CustomAgeLimitValidator&lt;/code&gt; validator to &lt;code&gt;EmployeeAgeDetails&lt;/code&gt; DTO:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  IsInt,
  IsNotEmpty,
  Validate,
} from 'class-validator';
import { CustomAgeLimitValidator } from '../custome-payload-validators/age-limit-validator';

export class EmployeeAgeDetails {
  @IsNotEmpty()
  @IsInt()
  @Validate(CustomAgeLimitValidator)
  age: number;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The  &lt;a href="https://github.com/typestack/class-validator#validation-decorators" rel="noopener noreferrer"&gt;validation decorators&lt;/a&gt; provided by the &lt;a href="https://github.com/typestack/class-validator#class-validator" rel="noopener noreferrer"&gt;class-validator&lt;/a&gt; provides us with the ability to pass our own error message. In our case, here’s how we will do it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Validate(CustomAgeLimitValidator, {message: 'Age limit violation! Employee age should be between 18 and 65 years'})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these changes if we try to feed our endpoint with below payload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "age": 16
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It would cause below error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "statusCode": 400,
    "message": [
        "Age limit violation! Employee age should be between 18 and 65 years"
    ],
    "error": "Bad Request"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Along with the ability to provide error message while applying validation decorators we can also provide default error message incase we forget or don’t feel the need to provide error message while applying decorator. To implement this case, we need to add optional &lt;code&gt;defaultMessage&lt;/code&gt; method inside our &lt;code&gt;CustomAgeLimitValidator&lt;/code&gt; class. Here’s the code example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  ValidatorConstraint,
  ValidatorConstraintInterface,
  ValidationArguments,
} from 'class-validator';

@ValidatorConstraint({ name: 'CustomAgeLimitValidator', async: false })
export class CustomAgeLimitValidator implements ValidatorConstraintInterface {
  validate(value: any): boolean {
    // Add validation logic here
    if (value &amp;lt; 18 || value &amp;gt; 65) return false;
    return true;
  }

  // optional method
  defaultMessage(args: ValidationArguments) {
    // Provide default error message if validation failed
    return `Age value ${args.value} caused age limit violated! Employee age should be between 18 and 65 years`;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if we feed the api with invalid age value&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "age": 16
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with above changes, the output error message would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "statusCode": 400,
    "message": [
        "Age value 16 caused age limit violation! Employee age should be between 18 and 65 years"
    ],
    "error": "Bad Request"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we are done! Hope you guys enjoyed it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7w3f7m2hkvomgvxjl773.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7w3f7m2hkvomgvxjl773.gif" alt="Adios"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Stay tuned, Thank You!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>nestjs</category>
      <category>security</category>
      <category>typescript</category>
    </item>
    <item>
      <title>NestJS Payload Validation</title>
      <dc:creator>Shubham Kadam</dc:creator>
      <pubDate>Wed, 02 Mar 2022 14:43:16 +0000</pubDate>
      <link>https://dev.to/shubham_kadam/nestjs-payload-validation-anf</link>
      <guid>https://dev.to/shubham_kadam/nestjs-payload-validation-anf</guid>
      <description>&lt;p&gt;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 &lt;a href="https://docs.nestjs.com/" rel="noopener noreferrer"&gt;NestJS&lt;/a&gt; documentation, looking for a potential solution.&lt;/p&gt;

&lt;p&gt;The NestJS documentation is very well written, and I was able to come up with a solution using &lt;a href="https://docs.nestjs.com/techniques/validation" rel="noopener noreferrer"&gt;ValidationPipe&lt;/a&gt; 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.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: &lt;br&gt;
Since this blog is not about NestJS itself, we will proceed, assuming you know how to write microservices using NestJS and what &lt;a href="https://docs.nestjs.com/controllers#request-payloads" rel="noopener noreferrer"&gt;DTOs&lt;/a&gt; are.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Before we begin, here’s the link to the &lt;a href="https://github.com/shubham16kadam/nestjs-payload-validation.git" rel="noopener noreferrer"&gt;github repo&lt;/a&gt; for the NestJS project which has the below mentioned code example for you to try locally.&lt;/p&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
   "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
      }
   ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DTOs for above payload would look like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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[];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below are the validations we need to apply to the mentioned payload:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Employee &lt;code&gt;name&lt;/code&gt; should only contain characters i.e. numeric values and symbols not allowed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;age&lt;/code&gt; should be integer value and greater than (&amp;gt;=) 18 and less than (&amp;lt;=) 65.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;address&lt;/code&gt; has below restrictions:

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;country&lt;/code&gt;, &lt;code&gt;state&lt;/code&gt;, &lt;code&gt;street&lt;/code&gt; and &lt;code&gt;city&lt;/code&gt; should only consist of characters.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;flatNo&lt;/code&gt; should be integer&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;projects&lt;/code&gt; should be an array of string.&lt;/li&gt;

&lt;li&gt;All the mentioned details must be provided i.e. empty values not allowed.&lt;/li&gt;

&lt;li&gt;There should be length related restriction on string values.&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;To get this job done, we will use &lt;a href="https://github.com/typestack/class-validator#validation-decorators" rel="noopener noreferrer"&gt;validation decorators&lt;/a&gt; provided by the &lt;a href="https://github.com/typestack/class-validator#class-validator" rel="noopener noreferrer"&gt;class-validator&lt;/a&gt; package.&lt;/p&gt;

&lt;h6&gt;
  
  
  Installation command for &lt;code&gt;class-validator&lt;/code&gt; package:
&lt;/h6&gt;

&lt;p&gt;&lt;code&gt;~ npm install class-validator --save&lt;/code&gt;&lt;br&gt;
The DTOs after changes (along with the imports) would look like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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(() =&amp;gt; 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(() =&amp;gt; WorkExperience)
  workExperience: WorkExperience[];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  Explanation
&lt;/h4&gt;

&lt;p&gt;The validation for input values of &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;age&lt;/code&gt; is straightforward. Let’s look at the attributes which are a bit complex.&lt;/p&gt;

&lt;h6&gt;
  
  
  &lt;em&gt;projects:&lt;/em&gt;
&lt;/h6&gt;

&lt;p&gt;projects attribute is of type array i.e. array of string, so the decorators &lt;code&gt;@IsArray()&lt;/code&gt; and &lt;code&gt;@ArrayNotEmpty()&lt;/code&gt; were applied accordingly.&lt;/p&gt;

&lt;p&gt;But, how do we validate values inside the array? For example, if we have an array:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;projects: [‘CustomerInsights’, ‘DemoPipeline’]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;How do we validate values ‘CustomerInsights’ and ‘DemoPipeline’ individually? How do we make sure that they satisfy all the necessary restrictions?&lt;/p&gt;

&lt;p&gt;The answer is, by passing validation option &lt;code&gt;each: true&lt;/code&gt; inside the desired decorator.&lt;/p&gt;

&lt;p&gt;why? Because,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If your field is an array and you want to perform validation of each item in the array you must specify a special &lt;code&gt;each: true&lt;/code&gt; decorator option.&lt;br&gt;
&lt;a href="https://github.com/typestack/class-validator#validating-arrays" rel="noopener noreferrer"&gt;NestJS Documentation &lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;h6&gt;
  
  
  &lt;em&gt;address&lt;/em&gt;:
&lt;/h6&gt;

&lt;p&gt;The &lt;code&gt;address&lt;/code&gt; attribute is not of primitive type, but instead, is an object which consists of nested object. Due to this, we applied &lt;code&gt;@ValidateNested()&lt;/code&gt; decorator along with &lt;code&gt;@Type()&lt;/code&gt; decorator, to indicate object type and applied validation separately to each of its nested objects (refer class &lt;code&gt;Address&lt;/code&gt;).&lt;/p&gt;

&lt;h6&gt;
  
  
  &lt;em&gt;workExperience&lt;/em&gt;:
&lt;/h6&gt;

&lt;p&gt;The &lt;code&gt;workExperience&lt;/code&gt; is similar to the &lt;code&gt;address&lt;/code&gt; 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 &lt;code&gt;each: true&lt;/code&gt; option to the &lt;code&gt;@ValidateNested()&lt;/code&gt; decorator i.e.&lt;code&gt;@ValidateNested({ each: true })&lt;/code&gt; and this will ensure that all the nested objects are validated.&lt;/p&gt;




&lt;p&gt;And we are done! Hope you guys enjoyed it.&lt;br&gt;
In my &lt;a href="https://dev.to/shubham_kadam/nestjs-custom-payload-validation-3hh7"&gt;next blog&lt;/a&gt;, I’ll talk about how to perform custom payload validation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please do checkout the project's &lt;a href="https://github.com/shubham16kadam/nestjs-payload-validation.git" rel="noopener noreferrer"&gt;github repo&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flrkxfg3e8x273fejah2d.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flrkxfg3e8x273fejah2d.gif" alt="Done"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Stay tuned, Thank You!
&lt;/h4&gt;

</description>
      <category>typescript</category>
      <category>security</category>
      <category>nestjs</category>
      <category>node</category>
    </item>
    <item>
      <title>DigDag - Schedule a Job(workflow) multiple times on same day</title>
      <dc:creator>Shubham Kadam</dc:creator>
      <pubDate>Sat, 15 Feb 2020 18:55:22 +0000</pubDate>
      <link>https://dev.to/shubham_kadam/digdag-schedule-a-job-workflow-multiple-times-on-same-day-11g7</link>
      <guid>https://dev.to/shubham_kadam/digdag-schedule-a-job-workflow-multiple-times-on-same-day-11g7</guid>
      <description>&lt;p&gt;Hey folks! So, I had a task of scheduling a Dashboard execution daily at 12.00 pm and 4.00 pm and was supposed to use &lt;a href="https://www.digdag.io/"&gt;DigDag Job Scheduler&lt;/a&gt;. But, after spending quite some time on &lt;a href="http://docs.digdag.io/getting_started.html"&gt;DigDag’s documentation&lt;/a&gt;, I couldn’t find anything relevant as per my requirement. Hence, I decided to try a workaround.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Instead of scheduling the Dashboard using a single workflow (the *.dig file), I can import/include the workflow into another workflow(s) and schedule it as per my need." &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Note: The below example is demonstrated on Ubuntu 18.04 (Linux). Please refer DigDag’s documentation for other platform-specific commands.&lt;/p&gt;

&lt;p&gt;Lets generate a sample digdag project &lt;em&gt;schedule-demo&lt;/em&gt; using command:&lt;/p&gt;

&lt;pre&gt;$ digdag init schedule-demo&lt;/pre&gt;

&lt;p&gt;The above command will create a workflow &lt;em&gt;schedule-demo.dig&lt;/em&gt; in schedule-demo directory/project with contents:&lt;/p&gt;

&lt;pre&gt;
timezone: UTC


+setup:

 echo&amp;gt;: start ${session_time}


+disp_current_date:

 echo&amp;gt;: ${moment(session_time).utc().format(‘YYYY-MM-DD HH:mm:ss Z’)}


+repeat:

 for_each&amp;gt;:

 order: [first, second, third]

 animal: [dog, cat]

 _do:

 echo&amp;gt;: ${order} ${animal}

 _parallel: true


+teardown:

 echo&amp;gt;: finish ${session_time}
&lt;/pre&gt;

&lt;p&gt;Let's schedule the above workflow for every one and two minutes on same day using file &lt;strong&gt;one_minute.dig&lt;/strong&gt; and &lt;strong&gt;two_minutes.dig&lt;/strong&gt; workflow.&lt;/p&gt;

&lt;p&gt;Create workflows one_minute.dig and two_minutes.dig in the project schedule-demo with below-mentioned contents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Workflow one_minute.dig:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;
!include : ‘schedule-demo.dig’

schedule:

 minutes_interval&amp;gt;: 1
&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;Workflow two_minute.dig:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;
!include : ‘schedule-demo.dig’

schedule:

 minutes_interval&amp;gt;: 2
&lt;/pre&gt;

&lt;p&gt;Now change your current working directory to &lt;em&gt;schedule-demo&lt;/em&gt; using the command:&lt;/p&gt;

&lt;pre&gt;$ cd {current_path}/schedule-demo/&lt;/pre&gt;

&lt;p&gt;then push the project &lt;em&gt;schedule-demo&lt;/em&gt; to digdag server using the command:&lt;/p&gt;

&lt;pre&gt;$ digdag push schedule-demo&lt;/pre&gt;

&lt;p&gt;(Note: On local Ubuntu setup, to start digdag server execute command &lt;em&gt;‘digdag server’&lt;/em&gt; on the terminal)&lt;/p&gt;

&lt;p&gt;If you are outside the project directory and want to push project use command:&lt;/p&gt;

&lt;pre&gt;$ digdag push schedule-demo --project /{path}/schedule-demo  --revision schedule-demo-v1&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;{path} =&amp;gt; path to the schedule-demo project&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then, launch a browser (any) and add URL ‘&lt;a href="http://localhost:65432/%E2%80%99"&gt;http://localhost:65432/’&lt;/a&gt; and under Workflow tab you will see the result similar to below image (you will have to wait for at least 5–6 minutes to get similar output as of mine):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ERCAF4Tx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/51qnzvdykqvqr9vui3lo.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ERCAF4Tx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/51qnzvdykqvqr9vui3lo.jpeg" alt="Alt Text" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you observe the image, the output with &lt;em&gt;ID 2&lt;/em&gt; and &lt;em&gt;ID 5&lt;/em&gt; has 2 minutes difference (refer column 'Last Attempt' ) and the value of Workflow is &lt;strong&gt;two-minute&lt;/strong&gt;. You will find similar result for the one-minute workflow (i.e. the execution time difference between every present and next workflow attempt will be 1 minute).&lt;/p&gt;

&lt;p&gt;P.S. There could be different ways to achieve the result demonstrated in the above example. This is just one of those :)&lt;/p&gt;

&lt;p&gt;If you enjoyed this blog, share it with your friends!&lt;/p&gt;

&lt;p&gt;Thank-You for reading!&lt;/p&gt;

&lt;p&gt;Sources: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.digdag.io/"&gt;https://www.digdag.io/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.digdag.io/getting_started.html"&gt;https://docs.digdag.io/getting_started.html&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.digdag.io/workflow_definition.html?highlight=include#include-another-file"&gt;https://docs.digdag.io/workflow_definition.html?highlight=include#include-another-file&lt;/a&gt;&lt;/p&gt;

</description>
      <category>digdag</category>
      <category>scheduler</category>
      <category>productivity</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
