Reputation: 300
I am working with the NestJS project, and want to log each and every request. I am using Fastify in my REST API. I made a nest middleware for getting request body:
import { HttpException, Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
const { httpVersion, headers, method, baseUrl, params, query, body } = req;
// body is Undefined!
console.log('Request Body...', body);
next();
}
}
When I print a log into the console, I got the output undefined.
app.module.ts:
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes('*');
}
}
main.ts:
import { NestFactory } from '@nestjs/core';
import {
FastifyAdapter,
NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter()
);
await app.listen(3000);
}
bootstrap()
Upvotes: 1
Views: 3629
Reputation: 111
When using Fastify with NestJS, Fastify use a package called middie
to support middleware like Express, but this compatibility doesn't extend fully to things like req.body
(BTW - same goes to req.params
and req.query
) within middleware in the same way as Express does.
When using Fastify under the hood in NestJS, these properties are not automatically populated in middleware because Fastify processes route parameters and query parameters after the middleware is executed. This is why you're seeing req.body
as undefined in the middleware.
To work around this, there are a couple of approaches you can take depending on what you're trying to accomplish.
One way to resolve the issue of not having access to req.params, req.query, or req.body in NestJS middleware when using Fastify is to use Fastify's onRequest hook. This hook is executed early in the lifecycle, and we can use it to attach params, query, and body to req.raw, which is the original request object.
This way, you can maintain compatibility with middleware that expects these properties (like in Express).
Step-by-Step Guide: Create a Utility Function to Attach Data to req.raw:
// utils/attach-request-data.ts
import { FastifyRequest, FastifyReply } from 'fastify';
/**
* Attaches params, query, and body from Fastify's request object to the raw request object.
* This ensures compatibility with middleware that expects these properties to be available.
*/
export function attachRequestDataToRaw(req: FastifyRequest, reply: FastifyReply, done: () => void) {
req.raw["params"]= req.params;
req.raw["query"]= req.query;
req.raw["body"]= req.body;
done();
}
Use the Utility Function in main.ts: In your main.ts, register the hook to attach the required data:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { FastifyInstance } from 'fastify';
import { attachRequestDataToRaw } from './utils/attach-request-data';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Get the Fastify instance from Nest's HTTP adapter
const fastifyInstance: FastifyInstance = app.getHttpAdapter().getInstance();
// Use the attachRequestDataToRaw function to attach params, query, and body
fastifyInstance.addHook('onRequest', attachRequestDataToRaw);
await app.listen(3000);
}
bootstrap();
Now - you can access req.raw.params, req.raw.query, and req.raw.body in any middleware by req.params, req.query and req.body :-)
Middleware in Fastify runs early in the request lifecycle, before Fastify has matched the route and populated the params, query, and body fields. By using the onRequest hook, we can manually copy the params, query, and body fields from Fastify's request object to req.raw, which is accessible throughout the rest of the request lifecycle, including in middleware.
Example: Using an Interceptor Interceptors in NestJS are applied after the routing process, so req.params, req.query, and req.body are accessible.
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { FastifyRequest } from 'fastify';
@Injectable()
export class ParamLoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest<FastifyRequest>();
// Now you can access request parameters, query, and body
console.log('Request Params:', request.params);
console.log('Query Params:', request.query);
console.log('Body:', request.body);
return next.handle();
}
}
ref
Upvotes: 1