From 1b4815138cd33799b89cc2336053d2c893230fa0 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Mon, 10 Apr 2023 22:31:02 +0530 Subject: [PATCH] feat: add filter for exception handler Signed-off-by: Pranav C --- packages/nocodb-nest/src/app.module.ts | 15 ++++- .../global-exception.filter.spec.ts | 7 +++ .../global-exception.filter.ts | 61 +++++++++++++++++++ .../nocodb-nest/src/helpers/catchError.ts | 18 +++--- 4 files changed, 90 insertions(+), 11 deletions(-) create mode 100644 packages/nocodb-nest/src/filters/global-exception/global-exception.filter.spec.ts create mode 100644 packages/nocodb-nest/src/filters/global-exception/global-exception.filter.ts diff --git a/packages/nocodb-nest/src/app.module.ts b/packages/nocodb-nest/src/app.module.ts index 213ef953f2..352e61e7d3 100644 --- a/packages/nocodb-nest/src/app.module.ts +++ b/packages/nocodb-nest/src/app.module.ts @@ -1,5 +1,7 @@ import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common'; +import { APP_FILTER } from '@nestjs/core'; import { Connection } from './connection/connection'; +import { GlobalExceptionFilter } from './filters/global-exception/global-exception.filter'; import { AuthModule } from './modules/auth/auth.module'; import { ExtractProjectIdMiddleware } from './middlewares/extract-project-id/extract-project-id.middleware'; import { UsersModule } from './modules/users/users.module'; @@ -8,7 +10,7 @@ import { MetaService } from './meta/meta.service'; import { UtilsModule } from './modules/utils/utils.module'; import { ProjectsModule } from './modules/projects/projects.module'; import { JwtStrategy } from './strategies/jwt.strategy'; -import { AuthGuard } from '@nestjs/passport'; +// import { AuthGuard } from '@nestjs/passport'; import { TablesModule } from './modules/tables/tables.module'; import { ViewsModule } from './modules/views/views.module'; import { FiltersModule } from './modules/filters/filters.module'; @@ -90,7 +92,16 @@ import { PluginsModule } from './modules/plugins/plugins.module'; PluginsModule, ], controllers: [], - providers: [Connection, MetaService, JwtStrategy, ExtractProjectIdMiddleware], + providers: [ + { + provide: APP_FILTER, + useClass: GlobalExceptionFilter, + }, + Connection, + MetaService, + JwtStrategy, + ExtractProjectIdMiddleware, + ], exports: [Connection, MetaService], }) export class AppModule { diff --git a/packages/nocodb-nest/src/filters/global-exception/global-exception.filter.spec.ts b/packages/nocodb-nest/src/filters/global-exception/global-exception.filter.spec.ts new file mode 100644 index 0000000000..167dc01053 --- /dev/null +++ b/packages/nocodb-nest/src/filters/global-exception/global-exception.filter.spec.ts @@ -0,0 +1,7 @@ +import { GlobalExceptionFilter } from './global-exception.filter'; + +describe('GlobalExceptionFilter', () => { + it('should be defined', () => { + expect(new GlobalExceptionFilter()).toBeDefined(); + }); +}); diff --git a/packages/nocodb-nest/src/filters/global-exception/global-exception.filter.ts b/packages/nocodb-nest/src/filters/global-exception/global-exception.filter.ts new file mode 100644 index 0000000000..33cb55d8e9 --- /dev/null +++ b/packages/nocodb-nest/src/filters/global-exception/global-exception.filter.ts @@ -0,0 +1,61 @@ +import { + ExceptionFilter, + Catch, + ArgumentsHost, + HttpException, +} from '@nestjs/common'; +import { Response } from 'express'; +import { + AjvError, + BadRequest, + extractDBError, + Forbidden, + InternalServerError, + NotFound, + NotImplemented, + Unauthorized, +} from 'src/helpers/catchError'; + +@Catch() +export class GlobalExceptionFilter implements ExceptionFilter { + catch(exception: any, host: ArgumentsHost) { + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + + // todo: error log + + const dbError = extractDBError(exception); + + if (dbError) { + return response.status(400).json(dbError); + } + + if (exception instanceof BadRequest) { + return response.status(400).json({ msg: exception.message }); + } else if (exception instanceof Unauthorized) { + return response.status(401).json({ msg: exception.message }); + } else if (exception instanceof Forbidden) { + return response.status(403).json({ msg: exception.message }); + } else if (exception instanceof NotFound) { + return response.status(404).json({ msg: exception.message }); + } else if (exception instanceof InternalServerError) { + return response.status(500).json({ msg: exception.message }); + } else if (exception instanceof NotImplemented) { + return response.status(501).json({ msg: exception.message }); + } else if (exception instanceof AjvError) { + return response + .status(400) + .json({ msg: exception.message, errors: exception.errors }); + } + + // handle different types of exceptions + if (exception instanceof HttpException) { + response.status(exception.getStatus()).json(exception.getResponse()); + } else { + response.status(500).json({ + statusCode: 500, + message: 'Internal server error', + }); + } + } +} diff --git a/packages/nocodb-nest/src/helpers/catchError.ts b/packages/nocodb-nest/src/helpers/catchError.ts index b81b80295e..b37ad50c58 100644 --- a/packages/nocodb-nest/src/helpers/catchError.ts +++ b/packages/nocodb-nest/src/helpers/catchError.ts @@ -1,6 +1,6 @@ import type { ErrorObject } from 'ajv'; -enum DBError { +export enum DBError { TABLE_EXIST = 'TABLE_EXIST', TABLE_NOT_EXIST = 'TABLE_NOT_EXIST', COLUMN_EXIST = 'COLUMN_EXIST', @@ -11,7 +11,7 @@ enum DBError { } // extract db errors using database error code -function extractDBError(error): { +export function extractDBError(error): { type: DBError; message: string; info: any; @@ -419,19 +419,19 @@ export default function ( }; } -class BadRequest extends Error {} +export class BadRequest extends Error {} -class Unauthorized extends Error {} +export class Unauthorized extends Error {} -class Forbidden extends Error {} +export class Forbidden extends Error {} -class NotFound extends Error {} +export class NotFound extends Error {} -class InternalServerError extends Error {} +export class InternalServerError extends Error {} -class NotImplemented extends Error {} +export class NotImplemented extends Error {} -class AjvError extends Error { +export class AjvError extends Error { constructor(param: { message: string; errors: ErrorObject[] }) { super(param.message); this.errors = param.errors;