I'm struggling with my custom exception filter which extends the Nestjs base exception filter. I found that I could inject HttpAdapterHost to provide the applicationRef argument for the BaseExceptionFilter constructor, but this doesn't seem to work: whenever super.catch is called, the app errors with applicationRef.isHeadersSent is not a function
.
ApplicationRef is a valid object at this point, but yep, it does not have an isHeadersSent method. What that actually implies, I'm not sure.
How do I approach putting together a custom filter like this? The docs suggest it ought to be possible.
import {
ArgumentsHost,
Catch,
HttpException,
Injectable,
} from '@nestjs/common';
import { BaseExceptionFilter, HttpAdapterHost } from '@nestjs/core';
import { Response } from 'express';
import { StructuredLogger } from './structured-logger.service';
// Catch any non-http exception and log it nicely with context instead of directly printing to stderr
@Catch()
@Injectable()
export class UncaughtExceptionFilter extends BaseExceptionFilter {
logger: StructuredLogger;
constructor(
readonly baseLogger: StructuredLogger,
private adapterHost: HttpAdapterHost,
) {
const instance = adapterHost.httpAdapter.getInstance();
super(instance);
this.logger = baseLogger.forClass('UncaughtExceptionFilter', 'uncaught');
}
catch(exception: any, host: ArgumentsHost) {
if (exception instanceof HttpException) {
super.catch(exception, host);
} else {
this.logger.error(exception, 'Uncaught exception', {});
//Respond manually to avoid printing to stderr
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const status = 500;
response.status(status).json({
statusCode: status,
message: 'Internal server error',
});
}
}
}
It seems to work when I use
adapterHost.httpAdapter
directly as the super constructor argument instead of calling .getInstance(). I'm guessing the base class relies on the abstract interface specifically somehow, but I don't really know the details here. More detailed explanations welcomed!