NestJS Middleware: Everything You Need to Know

NestJS Middleware: Everything You Need to Know

Your Complete Guide to Using Middleware in NestJS

When developing scalable server-side applications, NestJS is a powerful framework that leverages TypeScript and takes inspiration from Angular to provide a modular architecture. One of the crucial aspects of building robust applications is understanding and utilizing middleware effectively. This blog will dive into what middleware is, how it works in NestJS, and how you can implement it in your applications.

What is Middleware?

Middleware functions are functions that have access to the request and response objects, and the next() middleware function in the application’s request-response cycle. These functions can execute any code, make changes to the request and response objects, end the request-response cycle, and call the next middleware function.

Middleware in NestJS can be used for various tasks, such as:

  • Logging requests

  • Authenticating users

  • Parsing request bodies

  • Implementing CORS (Cross-Origin Resource Sharing)

  • Error handling

How Middleware Works in NestJS

In NestJS, middleware can be applied globally, at the module level, or for specific routes. Middleware in NestJS is very similar to Express middleware, making it familiar for those who have worked with Express.

Types of Middleware in NestJS

  1. Global Middleware: Applies to all routes in the application.

  2. Route Middleware: Applies to specific routes.

  3. Module Middleware: Applies to all routes in a specific module.

Creating Middleware in NestJS

To create middleware in NestJS, you need to implement the NestMiddleware interface or use a plain function. Here’s a step-by-step guide to creating and applying middleware in NestJS.

Step 1: Create Middleware

First, let’s create a simple logging middleware that logs the request method and URL.

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(`${req.method} ${req.url}`);
    next();
  }
}

Step 2: Apply Middleware

Global Middleware

To apply middleware globally, you need to use the configure method in the main application module.

import { Module, NestModule, MiddlewareConsumer } 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)
      .forRoutes('*'); // Apply to all routes
  }
}

Route Middleware

To apply middleware to specific routes, you can specify the routes in the forRoutes method.

import { Module, NestModule, MiddlewareConsumer } 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)
      .forRoutes('cats'); // Apply to routes that match 'cats'
  }
}

Module Middleware

To apply middleware to all routes within a specific module, you include the middleware configuration in that module.

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { LoggerMiddleware } from './logger.middleware';

@Module({
  controllers: [CatsController],
})
export class CatsModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes(CatsController); // Apply to all routes in CatsController
  }
}

Practical Examples of Middleware

Authentication Middleware

Here’s an example of an authentication middleware that checks if a user is authenticated.

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) {
    if (!req.headers.authorization) {
      throw new UnauthorizedException('You are not authorized.');
    }
    next();
  }
}

Error Handling Middleware

An error-handling middleware that catches and processes errors can also be implemented.

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

@Injectable()
export class ErrorHandlingMiddleware implements NestMiddleware {
  use(err: any, req: Request, res: Response, next: NextFunction) {
    console.error(err.stack);
    res.status(500).send('Something broke!');
  }
}
Conclusion
Middleware is a powerful feature in NestJS that allows you to handle requests and responses effectively. Whether you need to log requests, handle authentication, or manage errors, understanding how to create and apply middleware can significantly enhance your application.

By following the steps outlined in this guide, you can create and implement middleware in your NestJS applications to handle a variety of tasks, making your application more robust and maintainable. Happy coding!