Middleware in NestJS: Implementing and Using Middleware

@rnab
3 min readDec 23, 2024

--

NestJS is a powerful framework for building scalable and efficient server-side applications. It leverages TypeScript heavily and brings concepts like Dependency Injection, Decorators, and modular architecture, making it a comprehensive solution for backend development. One of the salient features in NestJS is middleware, which provides a way to run functions before the request is processed by the route handler. In this article, we’ll delve into how to implement and use middleware in NestJS.

What is Middleware?

Middleware in NestJS is similar to middleware in other frameworks like Express.js. It is essentially a function that receives the request and response objects, and a next() function. Middleware can be used for various purposes such as:

  • Logging every request for monitoring
  • Validating or transforming request data
  • Authenticating and authorizing requests
  • Conditionally routing the requests

Creating Middleware in NestJS

In NestJS, middleware can be easily created by implementing the NestMiddleware interface. Let’s dive into an example to better understand how to create and apply middleware in your NestJS application.

Example: Logging Middleware

First, let’s create a simple middleware to log details of every incoming request.

Step 1: Create the Middleware

To create our logging middleware, add a new file logging.middleware.ts to your src directory:

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

@Injectable()
export class LoggingMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
next(); // Call the next middleware in the chain
}
}

Step 2: Apply the Middleware

NestJS provides two methods to apply middleware: globally and locally.

Globally

To apply the middleware globally across your application, modify your main.ts file:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { LoggingMiddleware } from './logging.middleware';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(new LoggingMiddleware().use);
await app.listen(3000);
}
bootstrap();

Locally

Alternatively, you can apply middleware locally to specific routes or modules. Modify your app.module.ts file:

import { Module, MiddlewareConsumer, RequestMethod } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';
import { LoggingMiddleware } from './logging.middleware';

@Module({
imports: [CatsModule],
})
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggingMiddleware)
.forRoutes({ path: 'cats', method: RequestMethod.GET });
}
}

In the above code, the logging middleware is applied only to the GET requests on the ‘cats’ route.

Example: Authentication Middleware

Let’s create another example middleware for authenticating requests using a simple token check.

Step 1: Create the Middleware

Add a new file auth.middleware.ts to your src directory:

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

@Injectable()
export class AuthMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
const token = req.headers['authorization'];
if (!token || token !== 'mysecrettoken') {
throw new UnauthorizedException('Authorization token missing or invalid');
}
next(); // Call the next middleware in the chain
}
}

Step 2: Apply the Middleware

You can apply this middleware globally or locally, similar to the logging middleware. Let’s apply it locally to the ‘cats’ route for illustrative purposes.

Modify your app.module.ts file:

import { Module, MiddlewareConsumer, RequestMethod } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';
import { LoggingMiddleware } from './logging.middleware';
import { AuthMiddleware } from './auth.middleware';

@Module({
imports: [CatsModule],
})
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggingMiddleware, AuthMiddleware)
.forRoutes({ path: 'cats', method: RequestMethod.GET });
}
}

In the above example, both the logging and authentication middleware are applied to GET requests on the ‘cats’ route in sequence.

Conclusion

Middleware in NestJS is a versatile feature that can significantly enhance the functionality and robustness of your application. Whether it’s logging, authentication, or custom request processing, middleware provides a clean and modular way to handle such operations. By understanding how to create and apply middleware, you can better manage your request-response lifecycle, making your backend more effective and maintainable.

I hope this guide has given you a clear and practical understanding of middleware in NestJS. Start experimenting with middleware in your application and discover the possibilities it offers. Happy coding!

--

--

@rnab
@rnab

Written by @rnab

Typescript, Devops, Kubernetes, AWS, AI/ML, Algo Trading

No responses yet