.Djibril MUG

Middleware in nest.js

avatar

Djibril Mug

11 Mar 2023

4 min read


Middleware in nest.js

Before writing any line of code let's first define a middleware function in nest.js, a middleware function is a function that gets called before the route handler function, middleware functions have access to the request and response objects, a good definition, right? But what does that mean? Simply a middleware function is a function that gets triggered before the main request function, it can end the request life cycle or continue the request life cycle, not ending and not continuing will leave the request hanging which is a disaster for users' experience , a middleware function can modify the request object such as adding data reaching to a database just do everything that you can do in any normal function

Too much talking let's see that in action

new nest middleware

as you can see I have nest installed globally on my machine if you face any problems while creating the application please use the following guide from the official nest.js website https://docs.nestjs.com/

**Basic middleware ** For creating nest.js middleware you can use the class approach or use the function approach but for this example, we shall use the class base approach which is recommended by the nest.js team, in the example below we create a middleware function that takes the greeting string passed to our request body and check if the greeting is equal to hello, if the greeting is not hello the middleware function returns the request, and if the greeting passed into the request body is hello then the middleware function continues the request cycle and add a new data to our request body,

import { Injectable, NestMiddleware } from "@nestjs/common";
import { Request, Response, NextFunction } from "express";

@Injectable()
export class greetingMiddleware implements NestMiddleware {
    use(req: Request, res: Response, next: NextFunction) {
        if (req.body.greeting === 'hello') {
            req.body.randomNumber = Math.random();
            next()
        } else {
            return res.status(403).json({ message: "no greeting passed or not equal to hello " });
        }
    }
}

Dependency injection Like controllers and providers, middleware can also inject dependencies that are in the same module

Applying middlewares As me, you may think that middlewares are placed in the @module decorator but that is not the case, instead, we set them up using the configure() method of the module class, modules that contain middlewares have to implement the NestModule interface, let us see how to apply our greetingMiddlewar

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { greetingMiddleware } from './middleware/basicMiddleware';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(greetingMiddleware).forRoutes('greeting')
  }
}

In the example above we apply the greetingMiddlewar to the greeting route using the forRootes() method, we can also restrict the middleware to specific request methods by passing an object to the forRootes method containing the route path and the method, note that you are not restricted to one route you can pass your middleware to more than one route or pass it to the entire controller in the following example we see how to apply our middleware with a specific request method

import { Module, NestModule, MiddlewareConsumer,RequestMethod } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { greetingMiddleware } from './middleware/basicMiddleware';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(greetingMiddleware).forRoutes({ path: 'greeting', method: RequestMethod.GET })
  }
}

while using this method please do not forget to import RequestMethod it helps us to reference the targeted request method.

Applying to the entire controller In some cases you may want to pass your middleware to all routes available in your @controller, for doing that you need to pass your imported controller into the forRoot method as we did with routes

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(greetingMiddleware).forRoutes(AppController);
  }
}

Multiple middlewares You may also want to pass multiple middlewares that run sequentially, for having that in place you need to separate them with comma in the apply method, the given example is down bellow

export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(first(),second()).forRoutes(AppController);
  }
}

conclusion Middleware functions are very important concepts that every back-end developer should know and truly understand, you will probably need them in any back-end application you will have to build.

Thanks for reading and don't forget to follow if you find this content useful