NestJS Middleware: Everything You Need to Know
Your Complete Guide to Using Middleware in NestJS
Table of contents
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
Global Middleware: Applies to all routes in the application.
Route Middleware: Applies to specific routes.
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
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!