20-Nodejs Course 2023: Let's Create Our Own Request Handler
Tags: node, typescript, mongodb, fastify
Published: 2022-11-01 03:58:34

---
title: 20-Nodejs Course 2023: Let's Create Our Own Request Handler
published: true
description: 
series: Nodejs Course 2023
tags: nodejs, typescript, mongodb, fastify
#cover_image: 
# Use a ratio of 100:42 for best results.
---

Now we're good with Databases, let's head back to our request and make more sense of it.

## Request Handler

Basically what we're using so far is the  `request`  and  `reply`  objects from  `fastify`  to handle our requests. But we can do better than that. We can create our own request handler.

## Http Directory

Remember the `requests` directory we created? let's rename it to `http`, why??? because it will also contain a response handler so we can set both response and request in the same directory.

## Request class

Create `request.ts` file inside `src/core/http` directory and add the following code:

```ts
// src/core/http/request.ts
export class Request {
  /**
   * Fastify Request instance
   */
  public request: any;
  
  /**
   * Fastify response instance
   */
  public response: any;

  /**
   * Set request instance
   */
  public setRequest(request: any) {
    this.request = request;

    return this;
  }

  /**
   * Set response instance
   */
  public setResponse(response: any) {
    this.response = response;

    return this;
  }
}

const request = new Request();

export default request;
```

We added only two properties and two methods, these properties will contain the current instance of Fastify request and response, and the methods will set the current instance of Fastify request and response.

We also need to add the handler `controller` of current route so let's add it as well.

```ts
// src/core/http/request.ts
export class Request {
  /**
   * Fastify Request instance
   */
  public request: any;

  /**
   * Fastify response instance
   */
  public response: any;

  /**
   * Request handler
   */
  public handler: any;

  /**
   * Set request instance
   */
  public setRequest(request: any) {
    this.request = request;

    return this;
  }

  /**
   * Set response instance
   */
  public setResponse(response: any) {
    this.response = response;

    return this;
  }

  /**
   * Set handler instance
   */
  public setHandler(handler: any) {
    this.handler = handler;

    return this;
  }

  /**
   * Execute handler
   */
  public async execute() {
    return await this.handler(this, this.response);
  }
}

const request = new Request();

export default request;
```

## How this will work?

Let's take a step back at the `router.scan` method, it will loop through all the routes and register them to Fastify, but it will also set the handler of each route to the `request` instance we created.

Now Fastify handler will be the a custom handler of our own which we will create in a bit, that handler will receive the handler of route and return a callback, that callback will receive from Fastify the request and response objects, and we will set them to our `request` instance, then we will execute the handler of route and return the response.

But why would we do this? because we'll add more features to the request handler, also more features to the router, for instance we'll add a custom validation to the request handler `controller` if we want to validate the request before accessing the controller, also managing request data like casting numbers or booleans.

## Router Class

Open `src/core/router/index.ts` and update the scan method with the following code:

```ts
// src/core/router/index.ts


  /**
   * Register routes to the server
   */
  public scan(server: any) {
    this.routes.forEach(route => {
      const requestMethod = route.method.toLowerCase();
      const requestMethodFunction = server[requestMethod].bind(server);

      // 👇🏻 we changed `route.handler` to that new method handleRoute
      requestMethodFunction(route.path, this.handleRoute(route));
    });
  }

  /**
   * Handle the given route
   */
  private handleRoute(route: any) {
    return async (request: any, response: any) => {
      return await route.handler(request, response);
    };
  }
```

We just wrapped our handler in another method, that method will return the same exact response, except we added a little code to make it always async.

Now let's update our route handler to receive our request instance instead of Fastify request and response.

```ts
// src/routes/index.ts
import request from "core/http/request";
import { Route } from "./types";

export class Router {
  // ...
  /**
   * Register routes to the server
   */
  public scan(server: any) {
    this.routes.forEach(route => {
      const requestMethod = route.method.toLowerCase();
      const requestMethodFunction = server[requestMethod].bind(server);

      requestMethodFunction(route.path, this.handleRoute(route));
    });
  }

  /**
   * Handle the given route
   */
  private handleRoute(route: any) {
    return async (fastifyRequest: any, fastifyResponse: any) => {
      // update request instance
      request
        .setRequest(fastifyRequest)
        .setResponse(fastifyResponse)
        .setHandler(route.handler);

      // now execute the handler
      return await request.execute();
    };
  }
}

const router = Router.getInstance();

export default router;
```

We imported our request, then injected the current request and response handlers of Fastify to our request instance, then we set the handler of current route to our request instance, then we executed the handler and returned the response.

That execute method will call the handler and return the proper response accordingly.

## Request Executer

Navigating again to our request, let's create a new method called `execute` which will execute the handler of current route.

```ts
// src/core/http/request.ts

export class Request {
  /**
   * Fastify Request instance
   */
  public request: any;

  /**
   * Fastify response instance
   */
  public response: any;

  /**
   * Request handler
   */
  public handler: any;

  /**
   * Set request instance
   */
  public setRequest(request: any) {
    this.request = request;

    return this;
  }

  /**
   * Set response instance
   */
  public setResponse(response: any) {
    this.response = response;

    return this;
  }

  /**
   * Set handler instance
   */
  public setHandler(handler: any) {
    this.handler = handler;

    return this;
  }

  /**
   * Execute handler
   */
  public async execute() {
    return await this.handler(this, this.response);
  }
}

const request = new Request();

export default request;
```

Now it is perfect, except that the controller now will receive our request instance instead of Fastify request.

This means that now we can add any feature we want to our request instance, and it will be available to the controller.

## Conclusion

In this article we created a custom router, and we created a custom request instance, we also updated the router to use our request instance instead of Fastify request and response.

In our next article we'll start add some features to test it against our newly created request handler.

## Next Lesson

In the next lesson we'll start working with Database `Models`!

## 🎨 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)