NestJS inject into filter extending BaseExceptionFIlter

216 Views Asked by At

I want to make an exception filter that extends BaseExceptionFilter, to redirect non-http exceptions to my own logging service.

However, I have to inject my logger service, which means I have to give the filter a constructor:

@Catch()
@Injectable()
export class UncaughtExceptionFilter extends BaseExceptionFilter {
  constructor(
    private readonly logger: StructuredLogger,
    applicationRef: HttpServer,
  ) {
    super(applicationRef);
  }

  catch(exception: any, host: ArgumentsHost) {
    if (exception instanceof HttpException) {
      super.catch(exception, host);
    } else {
      // Have to respond manually to avoid super.catch writing to stderr
      this.logger.error(exception, 'uncaught');
      const ctx = host.switchToHttp();
      const response = ctx.getResponse<Response>();
      const status = 500;
      response.status(status).json({
        statusCode: status,
        message: 'Internal server error',
      });
    }
  }
}

Because I need to inject, I believe I must provide this class in a module using the APP_FILTER token.

However, BaseExceptionFilter wants an applicationRef argument, and https://stackoverflow.com/a/65473464/3896248 suggests this argument is mandatory. As shown, I've tried having my filter take an HttpServer argument in the hopes that this would be injected - no luck, the injection doesn't seem to provide it. What's the approach here?

I've seen solutions referencing an HTTP_SERVER_REF token -- doesn't seem to work now. I've also seen https://docs.nestjs.com/faq/http-adapter , but when attempting to inject HttpAdapterHost in an in-module as suggested, my application cannot find it to inject.

1

There are 1 best solutions below

0
On

The docs' injection method works, but you have to make really sure you import HttpAdapterHost from @nestjs/core and not @nestjs/common -- only the one exported from core will inject happily.

import {
  ArgumentsHost,
  Catch,
  HttpException,
  Injectable,
} from '@nestjs/common';
import { BaseExceptionFilter, HttpAdapterHost } from '@nestjs/core';

@Catch()
@Injectable()
export class UncaughtExceptionFilter extends BaseExceptionFilter {
  constructor(
    private readonly logger: StructuredLogger,
    httpAdapterHost: HttpAdapterHost,
  ) {
    const instance = httpAdapterHost.httpAdapter.getInstance();
    super(instance);
  }
[...]

(Credit https://stackoverflow.com/a/55483941/3896248 for pointing to the appropriate docs)