Skip to content

Commit

Permalink
feat: take full control over non-http exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
crazyoptimist committed Jun 13, 2024
1 parent 849c1af commit f6e5cee
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import 'source-map-support/register';

import { NestFactory, Reflector } from '@nestjs/core';
import { HttpAdapterHost, NestFactory, Reflector } from '@nestjs/core';
import { ClassSerializerInterceptor, ValidationPipe } from '@nestjs/common';
import { useContainer } from 'class-validator';

import { AppModule } from './modules/main/app.module';
import { setupSwagger } from './swagger';
import { TrimStringsPipe } from './modules/common/pipe/trim-strings.pipe';
import { APP_PORT, TOTAL_COUNT_HEADER_KEY } from './constants';
import { AllExceptionsFilter } from './modules/common/exception-filter/all-exceptions.filter';

declare const module: any;

Expand All @@ -29,6 +30,9 @@ async function bootstrap() {

useContainer(app.select(AppModule), { fallbackOnErrors: true });

const httpAdapter = app.get(HttpAdapterHost);
app.useGlobalFilters(new AllExceptionsFilter(httpAdapter));

await app.listen(APP_PORT);

if (module.hot) {
Expand Down
53 changes: 53 additions & 0 deletions src/modules/common/exception-filter/all-exceptions.filter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
HttpStatus,
} from '@nestjs/common';
import { HttpAdapterHost } from '@nestjs/core';
import { QueryFailedError } from 'typeorm';

type ResponseBody = {
statusCode: number;
message: string | string[];
error: string;
};

@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
constructor(private readonly httpAdapterHost: HttpAdapterHost) {}

catch(exception: unknown, host: ArgumentsHost): void {
// In certain situations `httpAdapter` might not be available in the
// constructor method, thus we should resolve it here.
const { httpAdapter } = this.httpAdapterHost;

const ctx = host.switchToHttp();

let statusCode: number;
let responseBody: ResponseBody;

// We now handle both HTTP and non-HTTP errors comprehensively.
if (exception instanceof HttpException) {
statusCode = exception.getStatus();
responseBody = exception.getResponse() as ResponseBody;
} else if (exception instanceof QueryFailedError) {
statusCode = HttpStatus.BAD_REQUEST;
responseBody = {
statusCode,
message: exception.message,
error: 'Database Query Failed Error',
};
} else {
statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
responseBody = {
statusCode,
message: (exception as Error).message,
error: 'Internal Server Error',
};
}

httpAdapter.reply(ctx.getResponse(), responseBody, statusCode);
}
}

0 comments on commit f6e5cee

Please sign in to comment.