23-Nodejs Course 2023: Validation Part I
Tags: node, typescript, mongodb, fastify
Published: 2022-11-02 04:11:13

---
title: 23-Nodejs Course 2023: Validation Part I
published: true
description: 
series: Nodejs Course 2023
tags: nodejs, typescript, mongodb, fastify
#cover_image: 
# Use a ratio of 100:42 for best results.
---

So far so good, now let's move to another important topic: Validation.

## Validation

Well, you'll start thinking now, what he will use for validation?, exactly as you thought, we'll do it from scratch xD, why? because its fun.

## Why Validation?

Any application will receive data from the user, and that data will be stored in the database, and that data will be used to perform some action, so it is important to validate that data, to ensure that it is correct, and that it is not `malicious`.

## How it works

The scenario will be like this:

- We attach the route handler to the route.
- If the route has a `validation` static property, then the request handler will start making the validation.
- If the validation fails, then the request handler will return an error.
- If the validation succeeds, then the request handler will be executed.

We'll do a simple validator that we can attach to the handler function `the controller function` a static variable we'll call it `validation` this will contain a `rules` object and we'll use it like this:

```ts
// src/apps/users/controllers/create-user.ts

export default function createUser(request) {
  const { name, email } = request.body;

  return {
    name,
    email
  }
}

createUser.validation = {
  rules: {
    name: ['required', 'string'],
    email: ['required', 'email'],
  }
};
```

And that it!

Now let's start create our simple validator.

## Request handler

If you remember we created earlier a Request class that handle the request, which has an `execute` method that calls our handler.

That executer we'll check inside it if the handler has a `validation` property, if so then we'll get it and start validating the request inputs in these rules.

If the validation passes, then we'll call the handler, if not we'll throw an error.

```ts
// src/core/http/request.ts
  /**
   * Execute the request
   */
  public async execute() {
    if (this.handler.validation) {
      const validationResult = new Validator(this, this.handler.validation);

      validationResult.scan();

      if (!validationResult.passes()) {
        return this.response.status(422).send(validationResult.errors());
      }
    }

    return await this.handler(this, this.response);
  }
```

We checked if the handler has a `validation` property, if so then we call the `Validator` class to validate the request inputs, this class will receive all inputs and the rules.

## Validator class

Now let's make the validator class, create `validator` folder inside `src/core` and create `index.ts` file inside it.

```ts
// src/core/validator/index.ts
import { Request } from "core/http/request";

export default class Validator {
  /**
   * Validation errors
   */
  protected errorsList: any = [];

  /**
   * Constructor
   */
  public constructor(
    protected readonly request: Request,
    protected readonly rules: any,
  ) {
    //
  }

  /**
   * Scan all the rules and validate the request
   */
  public scan() {}

  /**
   * Determine if the validation passes
   */
  public passes() {
    return this.errorsList.length === 0;
  }

  /**
   * Determine if the validation fails
   */
  public fails() {
    return !this.passes();
  }

  /**
   * Get errors list
   */
  public errors() {
    return this.errorsList;
  }
}
```

Here we added `errorsList` as an array that will contain all errors list, the constructor receives the request and the rules, and we added `scan` method that will scan all the rules and validate the request, and we added `passes` and `fails` methods that will determine if the validation passes or fails.

Now let's start the validation process.

> If you're wondering why we're using `readonly` because it do what is says, we don't want to modify it, we just want to read it.

> If you're wondering why we're using `protected` because we may make it in the future to be extended.

## Validation process

First we'll get all the inputs from the request that **needs to be validated**, and we'll loop over the rules and validate each input.

So we only need to get the input values for these rules, let's make a new method called `only` in the request class that will return the input values for these rules.

```ts
// src/core/http/request.ts
import { only } from "@mongez/reinforcements";

// class Request {
  // ..
  /**
   * Get only the given keys from the request
   */
  public only(keys: string[]) {
    return only(this.all(), keys);
  }
```

We used [only](https://github.com/hassanzohdy/reinforcements#getting-certain-values-from-object) utility to get only these given keys from the request.

Now let's head back to the validator class and get the inputs that needs to be validated.

```ts
// src/core/validator/index.ts

  /**
   * Scan all the rules and validate the request
   */
  public scan() {
    // get the request data for the rules inputs
    const inputValues = this.request.only(Object.keys(this.rules));

    // loop through the rules
    for (const input in this.rules) {
      // get the value for the input
      const inputValue = inputValues[input];
      // get the rules for the input
      const inputRules = this.rules[input];

      // Create a new rule handler to validate the input
      const rule = new Rule(input, inputValue, inputRules);

      // if the rule validation fails
      if (rule.validate().fails()) {
        // then add the rule errors to the errors list
        this.errorsList.push(rule.errors());
      }
    }
  }
```

I've put comments per each line i wrote above, first we'll get the input values directly from the request so we don't make multiple calls to the request class, then we made a loop over the rules (Remember it is an object not an array) so we used `for.in` loop to get the input as as the key, next we got the following data:

1. The input value
2. The input rules

Then we created a new `Rule` class to validate the input, and we called the `validate` method on it, if the validation fails then we'll add the errors to the errors list.

## Rule class

Now let's make the rule class, create `rule.ts` file inside `src/core/validator` folder.

```ts
// src/core/validator/rule.ts
export default class Rule {
  /**
   * Errors list
   */
  protected errorsList: any = [];

  /**
   * Constructor
   */
  public constructor(
    protected readonly input: string,
    protected readonly value: any,
    protected readonly rules: any,
  ) {
    //
  }
}
```

We'll stop at this point of the tutorial, and we'll continue in the next part.

## Conclusion

In this article we covered the concept behind how we would implement the validation process, and we made a simple validator that can validate the request inputs.

## 🎨 Project Repository

You can find the latest updates of this project on [Github](https://github.com/hassanzohdy/nodejs-2023)

## 😍 Join our community

Join our community on [Discord](https://discord.gg/pb2vmdfhGf) to get help and support (Node Js 2023 Channel).

## 🎞️ Video Course (Arabic Voice)

If you want to learn this course in video format, you can find it on [Youtube](https://www.youtube.com/playlist?list=PLGO8ntvxgiZMJc7RN2lIq9WmMOlWZGzmz), the course is in Arabic language.

## 💰 Bonus Content 💰

You may have a look at these articles, it will definitely boost your knowledge and productivity.

General Topics

- [Event Driven Architecture: A Practical Guide in Javascript](https://dev.to/hassanzohdy/event-driven-architecture-the-best-paradigm-that-i-love-to-work-with-in-javascript-and-node-js-1gnk)
- [Best Practices For Case Styles: Camel, Pascal, Snake, and Kebab Case In Node And Javascript](https://dev.to/hassanzohdy/best-practices-for-case-styles-camel-pascal-snake-and-kebab-case-in-node-and-javascript-55oi)
- [After 6 years of practicing MongoDB, Here are my thoughts on MongoDB vs MySQL
](https://dev.to/hassanzohdy/after-6-years-of-practicing-mongodb-here-are-my-thoughts-on-mongodb-vs-mysql-574b)

Packages & Libraries

- [Collections: Your ultimate Javascript Arrays Manager](https://dev.to/hassanzohdy/collections-your-ultimate-javascript-array-handler-3o15)
- [Supportive Is: an elegant utility to check types of values in JavaScript](https://dev.to/hassanzohdy/supportive-is-an-elegant-utility-to-check-types-of-values-in-javascript-1b3e)
- [Localization: An agnostic i18n package to manage localization in your project](https://dev.to/hassanzohdy/mongez-localization-the-simplest-way-to-translate-your-website-regardless-your-favorite-framework-4gi3)

 React Js Packages

- [useFetcher: easiest way to fetch data in React Js](https://dev.to/hassanzohdy/usefetcher-the-easiest-way-to-fetch-data-in-react-45o9)

Courses (Articles)

- [React Js: Let"s Create File Manager With React Js and Node Js](https://dev.to/hassanzohdy/lets-create-a-file-manager-from-scratch-with-react-and-typescript-chapter-i-a-good-way-to-expand-your-experience-5g4k)