I'm running some manual tests on a NestJS application I'm refactoring and just found an odd behaviour from nest's global exception filter. The developer who created this project used this as a exception filter:
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { HttpAdapterHost } from '@nestjs/core';
import { LoggerService } from '../../config/logger.service';
@Catch()
export class GlobalExceptionsFilter implements ExceptionFilter {
constructor(
private readonly httpAdapterHost: HttpAdapterHost,
private readonly logger: LoggerService,
) {}
catch(exception: Error, host: ArgumentsHost): void {
const { httpAdapter } = this.httpAdapterHost;
const ctx = host.switchToHttp();
const httpStatus =
exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
const responseBody = {
statusCode: httpStatus,
path: httpAdapter.getRequestUrl(ctx.getRequest()),
cause: `${exception.name}: ${exception.message}`,
timestamp: new Date().toISOString(),
};
this.logger.error(responseBody?.cause);
httpAdapter.reply(ctx.getResponse(), responseBody, httpStatus);
}
}
Which is almost exactly the same catch-everything filter example in Nest's docs, so it's very generic, indeed.
In a certain part of this project, there's a controller with something like this:
@OnEvent(Events.POTATO_EVENT)
async potatoMethod(payload) {
return await this.service.potatoMethod(payload);
Currently, there's no payload validation on the service's potatoMethod, so the controller receives a payload from another service using EventEmitter2 and forwards it to it's service, which then tries to fetch a record on the database by calling an ORM method.
If payload.potatoNumber is sent correctly, nothing wrong happens, but if I send payload.potatoNumber as undefined, the ORM will throw an error that will not be caught on that global filter.
The same thing doesn't happen if instead of using a @OnEvent() I just use a @Get() directly on the controller to turn it into an endpoint.
Currently, main looks something like this:
(async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
})();
I might be completely wrong, but this should only happen if the application is not using NestFactory.createMicroservice() on it's main.ts file, right? If positive, how exactly does microservices work natively in Nest?