wojciech.slodziak
wojciech.slodziak

Reputation: 351

How to make Dependency Injection work for global Exception Filter in NestJS?

I am trying to avoid using app.useGlobalFilters(new AllExceptionsFilter(...));, but I am struggling to make DI inject my custom LoggerService into AllExceptionsFilter.

I have my app module with LoggerModule imported and filter defined like this:

import { APP_FILTER } from '@nestjs/core';
...

@Module({
  imports: [LoggerModule],
  providers: [
    {
      provide: APP_FILTER,
      useClass: AllExceptionsFilter,
    },
  ],
})
export default class AppModule {}

Exception Filter (pretty much the same code as in nest docs):

import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
import LoggerService from '../modules/logger/logger.service';

@Catch()
export default class AllExceptionsFilter implements ExceptionFilter {
  constructor(private readonly loggerService: LoggerService) {}

  catch(exception: Error, host: ArgumentsHost): void {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const request = ctx.getRequest();

    console.log(this.loggerService);
    // this.loggerService.error(exception);

    const status =
      exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;

    response.status(status).json({
      statusCode: status,
      message: exception.message,
      path: request.url,
    });
  }
}

LoggerModule:

@Global()
@Module({
  providers: [LoggerService],
  exports: [LoggerService],
})
export default class LoggerModule {}

Can you point out what is wrong, and why LoggerService is not injected into my ExceptionFilter?

Documentation reference.

Upvotes: 8

Views: 5699

Answers (3)

Alexandre
Alexandre

Reputation: 7212

Just set the module scope to match your service scope:

@Module({
  imports: [LoggerModule],
  providers: [
    {
      provide: APP_FILTER,
      useClass: AllExceptionsFilter,
      scope: Scope.REQUEST, // this new line
    },
  ],
})

Upvotes: 0

Shuvro
Shuvro

Reputation: 242

AllExceptionsFilter file everything good, only change the main.ts file

const loggerService = app.get<LoggerService>(LoggerService);
app.useGlobalFilters(new AllExceptionsFilter(loggerService));

Upvotes: 3

wojciech.slodziak
wojciech.slodziak

Reputation: 351

I found out why this didn't work.

My LoggerService was annotated with: @Injectable({ scope: Scope.REQUEST })

I assume that because the instance was tied to request, it was already discarded at exception phase. Switching to @Injectable({ scope: Scope.TRANSIENT }) solved the issue.

Upvotes: 3

Related Questions