Search code examples
nestjsmiddleware

NestJS/ Is a middleware instantiated as a singleton?


I'm quite new to NestJS, so if I overlook something obvious, please forgive me.

Now I'm implementing a simple logger which logs request and response. In NestJS, you can put a middleware only before routing, so my middleware overwrite res.write and res.end so that response chunks will be pushed to an array in the middleware.

export class Logger implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    const originalResWrite = res.write;
    const originalResEnd = res.end;

    const chunks = [];

    res.write = (...chunk) => {
      chunks.push(Buffer.from(chunk[0]));
      originalResWrite.apply(res, chunk);
    };
    res.end = (...chunk) => {
      if (chunk[0]) {
        chunks.push(Buffer.from(chunk[0]));
      }

      const body = Buffer.concat(chunks).toString("utf8");

      console.log({
        requestBody: req.body,
        responseBody: JSON.parse(body) || body || {},
      });

      originalResEnd.apply(res, chunk);
    };
  }
}

However, if this middleware is instantiated as a singleton and shared by all requests--like Django middleware--, chunks Array will receive chunks from several streams, and the log will be totally messed up.

So, the problem is, how comsumer.apply instantiate a midddleware.

export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(Logger)
      .forRoutes('*');
  }
}

In NestJS, is a middleware instantiated as a singleton, or instantiated each time request comes? If you would answer my question, I would appreciate it.


Solution

  • Yes, by default providers are singleton in Nestjs, however, you can define the scope for your middleware using the options in the Injectable decorator. So you can add this before your middleware class definition

    @Injectable({ scope: Scope.REQUEST })
    

    Check out this link in the documentation and this answer on Stackoverflow.