Middlewares in Nest.js: Like a Piece of Cake 🍰
Tags: nestjs, typescript, node
Published: 2024-05-12 21:25:30

## Introduction

When creating APIs in Nest.js, you establish an endpoint for users to send their HTTP requests to. However, sometimes we need to manipulate the data sent by the user before it reaches our route handler function, or perhaps we want to log the data we will send as a response. This is where middlewares come into play.

Middlewares can perform various tasks; however, it's important to note that after creating and registering a middleware, it only executes before a HTTP request reaches the route handler function.

Talk is cheap, let's start coding! 

## Basic Middleware
For creating middleware in Nest.js, there are two approaches: class-based and function-based. Here, I'll demonstrate the class-based method.

In your Nest.js project, create a file named `logger.middleware.ts` and include the following base code:
```typescript
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
	  // Other stuff...
  }
}
```
At first glance, it might seem intimidating to those new to Nest.js, but I promise it's straightforward. Now, let's break down the important parts:

`LoggerMiddleware` is a class that implements the `NestMiddleware` interface. This interface requires the implementation of a function called `use()`, where both the `Request` and `Response` objects are available for use.

When a middleware is invoked, the code within the `use()` method is executed. This allows you to leverage the `Request` and `Response` objects for various purposes. Below is an example of a simple logger middleware:
```typescript
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
	console.log(`Executing middleware in path ${req.path}`);
	next();
}
```
As demonstrated, you have full control over the request object before it reaches the endpoint. The essential part of a middleware is the `next()` function, which should be called after at the end to ensure the application continues running smoothly.

## Attaching The Middleware
You can't register the middleware using the `@Module` decorator. Instead, you need to utilize a method called `configure()` within the module class. Additionally, the module class should implement the NestModule interface.
```typescript
import {
	MiddlewareConsumer,
	Module,
	NestModule,
	RequestMethod
} from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LoggerMiddleware } from './logger.middleware';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware) // if more that one split with ','
      .forRoutes({ path: '*', method: RequestMethod.ALL });
  }
}
```
"The main aspect is that you have to apply your middleware class with the to the consumer. You can specify which endpoints and request methods should invoke the middleware. In this example, all endpoints and request methods will trigger the middleware. I highly recommend reading the [official Nest.js documentation](https://docs.nestjs.com/middleware#applying-middleware) for more information on this.

## Conclusion
In conclusion, mastering the art of middleware usage, whether class-based or function-based, allows you to tailor your application's behavior to your specific requirements. By understanding how to attach middlewares and configure them within your modules, you can unlock the full potential of Nest.js and create robust, efficient APIs.