58-Nodejs Course 2023: Response Events
Tags: node, typescript, mongodb, fastify
Published: 2022-11-11 06:10:25

---
title: 58-Nodejs Course 2023: Response Events
published: true
description: 
series: Nodejs Course 2023
tags: nodejs, typescript, mongodb, fastify
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jjqw2z2etvea9o0lm75v.png
# Use a ratio of 100:42 for best results.
---

We have created our custom response class earlier. Now we want to add the response events.

## Response Events

Let's first review the response events list

* `response.sending`: Fired when the response is about to be sent.
* `response.sent`: Fired when the response has been sent.
* `response.success`: Fired when the response has been sent and the status code is `2xx`.
* `response.successCreate`: Fired when the response has been sent and the status code is `201`.
* `response.badRequest`: Fired when the response has been sent and the status code is `400`.
* `response.unauthorized`: Fired when the response has been sent and the status code is `401`.
* `response.throttled`: Fired when the response has been sent and the status code is `429`, which means the request has been throttled.
* `response.forbidden`: Fired when the response has been sent and the status code is `403`.
* `response.notFound`: Fired when the response has been sent and the status code is `404`.
* `response.serverError`: Fired when the response has been sent and the status code is `500`.
* `response.error`: Fired when the response has been sent and the status code is `4xx` or `5xx`.

The trick here is to check the status code at the `send` method whereas the `send` method will be used by all the response methods.

But let's first define our `ResponseEvent` Type

```ts
// src/http/type.ts
// ...

/**
 * Response Event Types
 */
export type ResponseEvent =
  /**
   * Triggered before sending the response
   */
  | "sending"
  /**
   * Triggered after sending the response regardless of the response status code
   */
  | "sent"
  /**
   * Triggered after sending the response if the response status code is 2xx
   */
  | "success"
  /**
   * Triggered after sending the response if the response status code is 201
   */
  | "successCreate"
  /**
   * Triggered after sending the response if the response status code is 400
   */
  | "badRequest"
  /**
   * Triggered after sending the response if the response status code is 401
   */
  | "unauthorized"
  /**
   * Triggered after sending the response if the response status code is 403
   */
  | "forbidden"
  /**
   * Triggered after sending the response if the response status code is 404
   */
  | "notFound"
  /**
   * Triggered after sending the response if the response status code is 429
   */
  | "throttled"
  /**
   * Triggered after sending the response if the response status code is 500
   */
  | "serverError"
  /**
   * Triggered after sending the response if the response status code is 4xx or 5xx
   */
  | "error";
```

We just set the type of the event. Now let's add the event emitter and listener to the `Response` class

```ts
// src/http/response.ts
import { ResponseEvent } from "./types";
import events, { EventSubscription } from '@mongez/events';

export class Response {
  // ...

  /**
   * Add a listener to the response event
   */
  protected on(event: ResponseEvent, listener: (...args: any[]) => void): EventSubscription {
    return events.subscribe(event, listener);
  }

  /**
   * Trigger the response event
   */
  protected trigger(event: ResponseEvent, ...args: any[]) {
    events.trigger(event, ...args);
  }

  /**
   * Send the response
   */
  public send(data: any, statusCode = 200) {
    // ...

    // trigger the sending event
    this.trigger('sending', data, statusCode);
    
    // send the response status and body
    this.baseResponse.status(statusCode).send(data);

    // trigger the sent event
    this.trigger('sent', data, statusCode);

    // trigger the success event if the status code is 2xx
    if (statusCode >= 200 && statusCode < 300) {
      this.trigger('success', data, statusCode);
    }

    // trigger the successCreate event if the status code is 201
    if (statusCode === 201) {
      this.trigger('successCreate', data, statusCode);
    }

    // trigger the badRequest event if the status code is 400
    if (statusCode === 400) {
      this.trigger('badRequest', data, statusCode);
    }

    // trigger the unauthorized event if the status code is 401
    if (statusCode === 401) {
      this.trigger('unauthorized', data, statusCode);
    }

    // trigger the forbidden event if the status code is 403
    if (statusCode === 403) {
      this.trigger('forbidden', data, statusCode);
    }

    // trigger the notFound event if the status code is 404
    if (statusCode === 404) {
      this.trigger('notFound', data, statusCode);
    }

    // trigger the throttled event if the status code is 429
    if (statusCode === 429) {
      this.trigger('throttled', data, statusCode);
    }

    // trigger the serverError event if the status code is 500
    if (statusCode === 500) {
      this.trigger('serverError', data, statusCode);
    }

    // trigger the error event if the status code is 4xx or 5xx
    if (statusCode >= 400) {
      this.trigger('error', data, statusCode);
    }
  }
}
```

So we added our usual methods, `on` and `trigger` to manage events, then in our `send` method we trigger the `sending` event, then we send the response, then we trigger the `sent` event, then we check the status code and trigger the appropriate event.

Now we can listen to any event from anywhere in our application.

```ts
// src/app/users/routes.ts
import response from 'core/http/response';

response.on('sending', (data, statusCode) => {
  console.log('sending', data, statusCode);
});

response.on('sent', (data, statusCode) => {
  console.log('sent', data, statusCode);
});

response.on('success', (data, statusCode) => {
  console.log('success', data, statusCode);
});

response.on('successCreate', (data, statusCode) => {
  console.log('successCreate', data, statusCode);
});
// and so on
```

## Importance of Response Events

You might think this is just useless addition to our base code, but actually it's not. It's very important to have this feature in our application.

Why? well let's see with a real world example.

Imagine that you want to add a value to each response regardless where the response is coming from any handler, for example i want to return the current user information with the request to make it easier for the frontend to use it and update current user information, we can do it like this.

```ts
// src/app/users/routes.ts
import response from 'core/http/response';
import user from 'core/auth/user';

response.on('sending', (data, statusCode) => {
    if (! data.user) {
        data.user = user.data();
    }
});
```

Which we'll actually do later in our application, but the point here is that we can add this value to all the responses regardless where the response is coming from.

We can actually improve it more, what about sending the current route handler to the response events? let's do it.

The route handler is sent to the request class which is updating the response class with `Fastify` reply instance, we can also update the response class with the route handler object.

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

// ...
  /**
   * Set route handler
   */
  public setRoute(route: Route) {
    this.route = route;

    // pass the route to the response object
    this.response.setRoute(route);

    return this;
  }
```

We added here a new line to pass the route to the response object, now we need to update the response class to accept the route.

```ts
// src/http/response.ts
import { Route } from "core/router/types";
// ...

export class Response {
    // ...
  /**
   * Current route
   */
  protected route!: Route;

  /**
   * Set route handler
   */
  public setRoute(route: Route) {
    this.route = route;

    return this;
  }
}
```

Actually there is something off here, we added a `statusCode` method to receive the `statusCode`, but we only checked for that one in the send class, so we need to make sure that both are synced with each other, let's improve it a little bit.

```ts
// src/http/response.ts

export class Response {
    // ...

  /**
   * Current status code
   */
  protected currentStatusCode?: number;

  /**
   * Set the status code
   */
  public setStatusCode(statusCode: number) {
    this.currentStatusCode = statusCode;

    return this;
  }
}
```

Now we updated the `status` method and renamed it to `setStatusCode` why? because its more readable :p, now we added a new property to store current status code.

Now let's update the `send` method

```ts
// src/http/response.ts

export class Response {
    // ...

  /**
   * Send the response
   */
  public send(data: any, statusCode?: number) {
    if (statusCode) {
      this.currentStatusCode = statusCode;
    }

    if (!this.currentStatusCode) {
      this.currentStatusCode = 200;
    }

    // trigger the sending event
    this.trigger("sending", this.currentStatusCode, data);

    this.baseResponse.status(this.currentStatusCode).send(data);

    // trigger the sent event
    this.trigger("sent", this.currentStatusCode, data);

    // trigger the success event if the status code is 2xx
    if (this.currentStatusCode >= 200 && this.currentStatusCode < 300) {
      this.trigger("success", data, this.currentStatusCode, this.route);
    }

    // trigger the successCreate event if the status code is 201
    if (this.currentStatusCode === 201) {
      this.trigger("successCreate", data, this.currentStatusCode, this.route);
    }

    // trigger the badRequest event if the status code is 400
    if (this.currentStatusCode === 400) {
      this.trigger("badRequest", data, this.currentStatusCode, this.route);
    }

    // trigger the unauthorized event if the status code is 401
    if (this.currentStatusCode === 401) {
      this.trigger("unauthorized", data, this.currentStatusCode, this.route);
    }

    // trigger the forbidden event if the status code is 403
    if (this.currentStatusCode === 403) {
      this.trigger("forbidden", data, this.currentStatusCode, this.route);
    }

    // trigger the notFound event if the status code is 404
    if (this.currentStatusCode === 404) {
      this.trigger("notFound", data, this.currentStatusCode, this.route);
    }

    // trigger the throttled event if the status code is 429
    if (this.currentStatusCode === 429) {
      this.trigger("throttled", data, this.currentStatusCode, this.route);
    }

    // trigger the serverError event if the status code is 500
    if (this.currentStatusCode === 500) {
      this.trigger("serverError", data, this.currentStatusCode, this.route);
    }

    // trigger the error event if the status code is 4xx or 5xx
    if (this.currentStatusCode >= 400) {
      this.trigger("error", data, this.currentStatusCode, this.route);
    }

    return this;
  }
}
```

Now we updated `send` method to accept the second argument as optional, if it is set, then we'll override current status code, if not then we need to check if there is no current status code, then we'll set it to `200`.

Now we can use it like this

```ts
// src/app/users/routes.ts

import response from 'core/http/response';

response.on('sending', (statusCode, data, route) => {
  console.log('sending', statusCode, data);
});
```

And that's it, now we can listen to any event from anywhere in our application.

## 🎨 Conclusion

In this article, we saw how to use response events how important they are, we also modified the status code to be more controlled and we added a new property to set the status code.

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