import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus, } from '@nestjs/common'; import { AppError } from './app-error'; import { ErrorCodeResolver } from './app-error/models'; import { AppLogger } from '../logger'; import { HttpArgumentsHost } from '@nestjs/common/interfaces'; import { IErrorResponse } from './app-error/models/interfaces'; import { HttpError } from './app-error/http-error'; import { SystemError } from './app-error/system-error'; import { ErrorType } from './app-error/models/enums'; import { ErrorCodeDetails } from './app-error/models/interfaces'; import { ErrorCode } from './app-error/models/enums'; import { AuthorizationError } from './app-error/authorization-error'; @Catch(Error) export class AppExceptionsFilter implements ExceptionFilter { private readonly TAG: string = `${this.constructor.name}`; catch(exception: any, host: ArgumentsHost) { const ctx: HttpArgumentsHost = host.switchToHttp(); const response = ctx.getResponse(); const request = ctx.getRequest(); let errorResponse: IErrorResponse; switch (true) { case exception instanceof AppError: errorResponse = this.buildAppErrorResponse(exception); break; case exception instanceof HttpException: errorResponse = this.buildHttpExceptionResponse(exception); break; default: errorResponse = this.buildUnknownErrorResponse(exception); } errorResponse.timestamp = new Date().toISOString(); errorResponse.path = request.url; const httpStatusResponse: number = errorResponse.statusCode ? errorResponse.statusCode : HttpStatus.INTERNAL_SERVER_ERROR; response .status(httpStatusResponse) .json(errorResponse); } private buildAppErrorResponse(exception: AppError): IErrorResponse { switch (exception.constructor) { case HttpError: return this.buildHttpErrorResponse(exception); case SystemError: return this.buildSystemErrorResponse(exception); case AuthorizationError: return this.buildAuthorizationErrorResponse(exception); default: return this.buildAppErrorGenericResponse(exception); } } private buildAuthorizationErrorResponse(exception: AuthorizationError): IErrorResponse { const { errorCode } = exception; const { message, status } = ErrorCodeResolver.getErrorCode(ErrorType.UNAUTHORIZED, errorCode); const messageToLog: string = `\nUNAUTHORIZED error occurred \nError Message - ${message} \nError Code - ${errorCode}`; AppLogger.error(messageToLog, this.TAG); return { statusCode: status, timestamp: '', path: '', }; } private buildHttpExceptionResponse(exception: HttpException): IErrorResponse { const { message, stack } = exception; AppLogger.error(stack, this.TAG); return { statusCode: HttpStatus.NOT_FOUND, message, timestamp: '', path: '', }; } private buildHttpErrorResponse(exception: HttpError): IErrorResponse { const { stack, errorCode, description } = exception; const { message, status, hideMessage } = ErrorCodeResolver.getErrorCode(ErrorType.HTTP, errorCode); const errorDescription: string = description ? `\nError Description - ${description}` : ''; const messageToLog: string = `\nHTTP error occurred \nError Message - ${message} \nError Code - ${errorCode} ${errorDescription} \nError Trace - ${stack}`; AppLogger.error(messageToLog, this.TAG); if (hideMessage) { return { errorCode: exception.errorCode, statusCode: status, description, timestamp: '', path: '', }; } return { errorCode: exception.errorCode, statusCode: status, message, description, timestamp: '', path: '', }; } private buildSystemErrorResponse(exception: SystemError): IErrorResponse { const { stack, errorCode, description } = exception; const { message, status }: ErrorCodeDetails = ErrorCodeResolver.getErrorCode(ErrorType.SYSTEM, errorCode); const errorDescription: string = description ? `\nError Description - ${description}` : ''; const messageToLog: string = `\nSYSTEM error occurred \nError Message - ${message} \nError Code - ${errorCode} ${errorDescription} \nError Trace - ${stack}`; AppLogger.error(messageToLog, this.TAG); return { errorCode: exception.errorCode, statusCode: status, message, description, timestamp: '', path: '', }; } private buildUnknownErrorResponse(exception: any): IErrorResponse { const { message, status }: ErrorCodeDetails = ErrorCodeResolver.getErrorCode(ErrorType.UNKNOWN, ErrorCode.UNKNOWN); const messageToLog: string = `\nUnhandled Error occurred \n Error Message - ${message} \nError Trace - ${exception.stack}`; const defaultErrorMessage: string = `Server handling with an unknown error`; AppLogger.error(messageToLog, this.TAG); return { errorCode: exception.errorCode, statusCode: status, message: defaultErrorMessage, timestamp: '', path: '', }; } private buildAppErrorGenericResponse(exception: AppError): IErrorResponse { const { stack, errorCode, errorType } = exception; const { message, status }: ErrorCodeDetails = ErrorCodeResolver.getErrorCode(errorType, errorCode); const messageToLog: string = `\nBAD REQUEST error occurred \nError Message - ${message} \nError Code - ${errorCode} \nError Trace - ${stack}`; AppLogger.error(messageToLog, this.TAG); return { errorCode: exception.errorCode, statusCode: status, message, timestamp: '', path: '', }; } }