Delving Developer

Mastering NestJS Middleware: Implementation Guide

Eddie Cunningham
Eddie Cunningham
3 min readNestJS
Cover Image for Mastering NestJS Middleware: Implementation Guide

Navigating the world of backend development, specifically using the Node.js framework NestJS, can be a game changer for developers. Known for its efficiency and scalability, NestJS is styled after Angular, making it intuitive for developers familiar with the Angular ecosystem. One integral part of NestJS applications is the use of middleware—a crucial component in controlling the request-response cycle. This guide will delve into understanding how NestJS middleware functions, provide complex examples, and show how to implement it effectively.

Understanding NestJS Middleware

In NestJS, middleware acts as a function operating during the request and response cycle, essentially intercepting the requests sent to a server. This allows developers to execute baseline processing on requests, filter requests, inject properties into requests, log requests, and much more. Middleware can either be third-party or custom-made to suit the specific needs of applications.

Types of Middleware

  1. Application Middleware: Executed for every route handler.
  2. Router Middleware: Binds to a specific router, allowing selective execution.

The Essentials of Middleware Implementation

To implement middleware in NestJS, follow these steps:

  1. Create a Middleware: Define a middleware class implementing the NestMiddleware interface.

    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(`Request...`);
        next();
      }
    }
    
  2. Apply Middleware: Include it in the module using the configure method from the NestModule interface.

    import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
    import { LoggerMiddleware } from './logger.middleware';
    
    @Module({
      imports: [],
    })
    export class AppModule implements NestModule {
      configure(consumer: MiddlewareConsumer) {
        consumer
          .apply(LoggerMiddleware)
          .forRoutes('cats');
      }
    }
    

Complex Middleware Use Case

To illustrate the capabilities and flexibility of middleware within NestJS, let's tackle a complex use case—a request validation middleware that checks for valid API keys before proceeding with the request.

Step 1: Define the Validation Middleware

The middleware will check incoming requests for a valid API key and either allow or deny access based on its presence and validity.

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

@Injectable()
export class ApiKeyMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    const apiKey = req.headers['x-api-key'];
    if (!apiKey || apiKey !== 'my-secret-key') {
      throw new UnauthorizedException('Invalid API key');
    }
    next();
  }
}

Step 2: Integrate Middleware into Routes

Incorporate this middleware into appropriate application routes to ensure requests are authenticated before reaching their controllers.

import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';
import { ApiKeyMiddleware } from './apikey.middleware';

@Module({
  imports: [],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(ApiKeyMiddleware)
      .forRoutes('*');  // Apply globally or specify certain routes
  }
}

Middleware and the Middleware Stack

NestJS allows stacking multiple middleware to create a robust pipeline. This functionality means that you can handle logging, authentication, error handling, and more in a streamlined, performant manner. Middleware runs in sequence from top to bottom within the stack, allowing intricate request manipulation through a layered approach.

Conclusion

Middleware is a powerful aspect of NestJS, unlocking numerous possibilities for enhancing application capabilities. Whether for logging, validation, or manipulation, effectively leveraging middleware can greatly optimize your backend structuring and workflow. By following this guide on NestJS middleware, web developers can create more secure and efficient applications, leading to refined user experiences and impactful application performance.

For more information, delve into the NestJS documentation to explore additional features and applications of middleware in your development journey.