To create functional middleware for APIs in Nestjs, you need to do 3 things:
- First, you need to create and export a function with
3
parameters to receive therequest
object, theresponse
object, and thenext
function. In our case, we will be using the defaultExpress
middleware objects. Therequest
object contains all the properties/methods to manipulate the incoming request, theresponse
object contains all the properties/methods to manipulate the response for the request, and thenext()
function is used to notify and hand over the execution to other middlewares down the request/response lifecycle. This specific middleware is calledfunctional
because we are defining the middleware in the form of a function. These can also be created using a class-based approach. - Secondly, you need to register the newly created middleware using the
apply()
method of theMiddlewareConsumer
interface and pass the middleware as its argument inside theconfigure()
method of the feature module or root/core module class of the application. - Finally, you also need to set the routes for which the middleware needs to work upon by chaining the
forRoutes()
method after theapply()
method and passing the route string or theController
class.
TL;DR
Filepath: src/middlewares/application-logger.middleware.ts
// Express types for the req, res, and next variables
import { Request, Response, NextFunction } from "express";
// middleware to log the url and the host url of the incoming requests
export function ApplicationLogger(
req: Request,
res: Response,
next: NextFunction
) {
// log the url and the host url from the `req` object
console.log({
Host: req.host,
URL: req.url,
});
next();
}
Filepath: src/app.module.ts
import { MiddlewareConsumer, Module, NestModule } from "@nestjs/common";
import { GreetController } from "./greet/greet.controller";
import { GreetService } from "./greet/greet.service";
import { ApplicationLogger } from "./middlewares/application-logger.middleware";
@Module({
imports: [],
controllers: [GreetController], // <- add controller here
providers: [GreetService], // <- add provider here
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
// apply the `ApplicationLogger` middleware
// to the `/greet` API endpoints using the `forRoutes()` method.
consumer.apply(ApplicationLogger).forRoutes(GreetController);
}
}
To understand it better, let's make a small middleware and use it for an API.
For example, let's say we need to create a logging middleware where we need to log the url
and the hostname
of the incoming request.
To do that, let's first create a functional middleware
by creating and exporting a function called ApplicationLogger
with 3
parameters namely req
, res
, and next
. The req
, res
, and next
variables are Express middleware
object variables.
The types for the req
, res
object variables, and the next
function can be imported from the express
module which is already installed with Nestjs by default.
We will be creating the middleware inside the src/middlewares
directory.
It can be done like this,
Filepath: src/middlewares/application-logger.middleware.ts
// Express types for the req, res, and next variables
import { Request, Response, NextFunction } from "express";
// middleware to log the url and the host url of the incoming requests
export function ApplicationLogger(
req: Request,
res: Response,
next: NextFunction
) {}
Now inside the ApplicationLogger
function, we can log the url and the host url from the req
object variable using the console.log()
method.
It can be done like this,
Filepath: src/middlewares/application-logger.middleware.ts
// Express types for the req, res, and next variables
import { Request, Response, NextFunction } from "express";
// middleware to log the url and the host url of the incoming requests
export function ApplicationLogger(
req: Request,
res: Response,
next: NextFunction
) {
// log the url and the host url from the `req` object
console.log({
Host: req.host,
URL: req.url,
});
}
Finally, to hand over the execution of the code to other middlewares/controllers down the request/response lifecycle, we can call the next()
function.
It can be done like this,
Filepath: src/middlewares/application-logger.middleware.ts
// Express types for the req, res, and next variables
import { Request, Response, NextFunction } from "express";
// middleware to log the url and the host url of the incoming requests
export function ApplicationLogger(
req: Request,
res: Response,
next: NextFunction
) {
// log the url and the host url from the `req` object
console.log({
Host: req.host,
URL: req.url,
});
next();
}
We have already made an API for the /greet
- GET
API.
To know more about creating a GET
API, see the blog on How to make a simple GET request or an API endpoint in Nestjs?
Now we need to register the ApplicationLogger
middleware for the /greet
API endpoints. To do that, we need to use the apply()
method from the MiddlewareConsumer
interface and pass the ApplicationLogger
middleware as an argument to the method inside the configure()
of the root module of the application.
It can be done like this,
Filepath: src/app.module.ts
import { MiddlewareConsumer, Module, NestModule } from "@nestjs/common";
import { GreetController } from "./greet/greet.controller";
import { GreetService } from "./greet/greet.service";
import { ApplicationLogger } from "./middlewares/application-logger.middleware";
@Module({
imports: [],
controllers: [GreetController], // <- add controller here
providers: [GreetService], // <- add provider here
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
// apply the `ApplicationLogger` middleware
consumer.apply(ApplicationLogger);
}
}
NOTE: If you look at the code above, you can see that the AppModule
class implements the NestModule
interface. This is needed for every module that is using any middleware.
We have applied the middlewares, but haven't told Nestjs which API endpoints we need to apply the middlewares to. To do that, we can chain the forRoutes()
method to the apply()
method and pass the GreetController
class as an argument to it. This will instruct Nestjs that the ApplicationLogger
will only need to be called for /greet
API endpoints.
It can be done like this,
Filepath: src/app.module.ts
import { MiddlewareConsumer, Module, NestModule } from "@nestjs/common";
import { GreetController } from "./greet/greet.controller";
import { GreetService } from "./greet/greet.service";
import { ApplicationLogger } from "./middlewares/application-logger.middleware";
@Module({
imports: [],
controllers: [GreetController], // <- add controller here
providers: [GreetService], // <- add provider here
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
// apply the `ApplicationLogger` middleware
// to the `/greet` API endpoints using the `forRoutes()` method.
consumer.apply(ApplicationLogger).forRoutes(GreetController);
}
}
Now if you go to the /greet
endpoint in the browser, you can see the Host
and the URL
of the incoming request being printed onto the terminal.
The terminal output might look similar to the below,
{ Host: '0y59ux-3000.preview.csb.app', URL: '/greet' }
We have successfully added the ApplicationLogger
functional middleware for /greet
API endpoints in Nestjs. Yay 🥳!
See the above code live in codesandbox.
That's all 😃.