From f99617dd6be4839cd8ce503b926f4adf7f42c027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20My=C5=9Bliwiec?= Date: Thu, 21 Nov 2024 10:09:43 +0100 Subject: [PATCH] feat(common): introduce intrinsic exception --- packages/common/exceptions/http.exception.ts | 11 +++++-- packages/common/exceptions/index.ts | 33 ++++++++++--------- .../common/exceptions/intrinsic.exception.ts | 7 ++++ .../core/exceptions/base-exception-filter.ts | 5 ++- .../exceptions/external-exception-filter.ts | 7 ++-- .../exceptions/base-rpc-exception-filter.ts | 13 ++++++-- .../exceptions/base-ws-exception-filter.ts | 12 +++++-- 7 files changed, 61 insertions(+), 27 deletions(-) create mode 100644 packages/common/exceptions/intrinsic.exception.ts diff --git a/packages/common/exceptions/http.exception.ts b/packages/common/exceptions/http.exception.ts index 143df233eed..0ed8b8dd2af 100644 --- a/packages/common/exceptions/http.exception.ts +++ b/packages/common/exceptions/http.exception.ts @@ -3,6 +3,7 @@ import { HttpExceptionBodyMessage, } from '../interfaces/http/http-exception-body.interface'; import { isNumber, isObject, isString } from '../utils/shared.utils'; +import { IntrinsicException } from './intrinsic.exception'; export interface HttpExceptionOptions { /** original cause of the error */ @@ -23,7 +24,13 @@ export interface DescriptionAndOptions { * * @publicApi */ -export class HttpException extends Error { +export class HttpException extends IntrinsicException { + /** + * Exception cause. Indicates the specific original cause of the error. + * It is used when catching and re-throwing an error with a more-specific or useful error message in order to still have access to the original error. + */ + public cause: unknown; + /** * Instantiate a plain HTTP Exception. * @@ -68,8 +75,6 @@ export class HttpException extends Error { this.initCause(); } - public cause: unknown; - /** * Configures error chaining support * diff --git a/packages/common/exceptions/index.ts b/packages/common/exceptions/index.ts index ab2a948b17b..554218336df 100644 --- a/packages/common/exceptions/index.ts +++ b/packages/common/exceptions/index.ts @@ -1,22 +1,23 @@ +export * from './bad-gateway.exception'; export * from './bad-request.exception'; -export * from './http.exception'; -export * from './unauthorized.exception'; -export * from './method-not-allowed.exception'; -export * from './not-found.exception'; -export * from './forbidden.exception'; -export * from './not-acceptable.exception'; -export * from './request-timeout.exception'; export * from './conflict.exception'; +export * from './forbidden.exception'; +export * from './gateway-timeout.exception'; export * from './gone.exception'; -export * from './payload-too-large.exception'; -export * from './unsupported-media-type.exception'; -export * from './unprocessable-entity.exception'; -export * from './internal-server-error.exception'; -export * from './not-implemented.exception'; export * from './http-version-not-supported.exception'; -export * from './bad-gateway.exception'; -export * from './service-unavailable.exception'; -export * from './gateway-timeout.exception'; +export * from './http.exception'; export * from './im-a-teapot.exception'; -export * from './precondition-failed.exception'; +export * from './internal-server-error.exception'; +export * from './intrinsic.exception'; +export * from './method-not-allowed.exception'; export * from './misdirected.exception'; +export * from './not-acceptable.exception'; +export * from './not-found.exception'; +export * from './not-implemented.exception'; +export * from './payload-too-large.exception'; +export * from './precondition-failed.exception'; +export * from './request-timeout.exception'; +export * from './service-unavailable.exception'; +export * from './unauthorized.exception'; +export * from './unprocessable-entity.exception'; +export * from './unsupported-media-type.exception'; diff --git a/packages/common/exceptions/intrinsic.exception.ts b/packages/common/exceptions/intrinsic.exception.ts new file mode 100644 index 00000000000..cb09b8e61a8 --- /dev/null +++ b/packages/common/exceptions/intrinsic.exception.ts @@ -0,0 +1,7 @@ +/** + * Exception that represents an intrinsic error in the application. + * When thrown, the default exception filter will not log the error message. + * + * @publicApi + */ +export class IntrinsicException extends Error {} diff --git a/packages/core/exceptions/base-exception-filter.ts b/packages/core/exceptions/base-exception-filter.ts index 12735f13666..cc7c8611fcd 100644 --- a/packages/core/exceptions/base-exception-filter.ts +++ b/packages/core/exceptions/base-exception-filter.ts @@ -5,6 +5,7 @@ import { HttpServer, HttpStatus, Inject, + IntrinsicException, Logger, Optional, } from '@nestjs/common'; @@ -68,7 +69,9 @@ export class BaseExceptionFilter implements ExceptionFilter { applicationRef.end(response); } - return BaseExceptionFilter.logger.error(exception); + if (!(exception instanceof IntrinsicException)) { + BaseExceptionFilter.logger.error(exception); + } } public isExceptionObject(err: any): err is Error { diff --git a/packages/core/exceptions/external-exception-filter.ts b/packages/core/exceptions/external-exception-filter.ts index 076b6a970a9..3648613de5c 100644 --- a/packages/core/exceptions/external-exception-filter.ts +++ b/packages/core/exceptions/external-exception-filter.ts @@ -1,10 +1,13 @@ -import { ArgumentsHost, HttpException, Logger } from '@nestjs/common'; +import { ArgumentsHost, IntrinsicException, Logger } from '@nestjs/common'; export class ExternalExceptionFilter { private static readonly logger = new Logger('ExceptionsHandler'); catch(exception: T, host: ArgumentsHost): R | Promise { - if (exception instanceof Error && !(exception instanceof HttpException)) { + if ( + exception instanceof Error && + !(exception instanceof IntrinsicException) + ) { ExternalExceptionFilter.logger.error(exception); } throw exception; diff --git a/packages/microservices/exceptions/base-rpc-exception-filter.ts b/packages/microservices/exceptions/base-rpc-exception-filter.ts index 849bc9ac2ff..2c5d94ba612 100644 --- a/packages/microservices/exceptions/base-rpc-exception-filter.ts +++ b/packages/microservices/exceptions/base-rpc-exception-filter.ts @@ -1,5 +1,10 @@ /* eslint-disable prefer-spread */ -import { ArgumentsHost, Logger, RpcExceptionFilter } from '@nestjs/common'; +import { + ArgumentsHost, + IntrinsicException, + Logger, + RpcExceptionFilter, +} from '@nestjs/common'; import { isObject } from '@nestjs/common/utils/shared.utils'; import { MESSAGES } from '@nestjs/core/constants'; import { Observable, throwError as _throw } from 'rxjs'; @@ -26,8 +31,10 @@ export class BaseRpcExceptionFilter public handleUnknownError(exception: T, status: string) { const errorMessage = MESSAGES.UNKNOWN_EXCEPTION_MESSAGE; - const logger = BaseRpcExceptionFilter.logger; - logger.error.apply(logger, [exception]); + if (!(exception instanceof IntrinsicException)) { + const logger = BaseRpcExceptionFilter.logger; + logger.error(exception); + } return _throw(() => ({ status, message: errorMessage })); } diff --git a/packages/websockets/exceptions/base-ws-exception-filter.ts b/packages/websockets/exceptions/base-ws-exception-filter.ts index 6f1b74dee36..2b9961a7393 100644 --- a/packages/websockets/exceptions/base-ws-exception-filter.ts +++ b/packages/websockets/exceptions/base-ws-exception-filter.ts @@ -1,4 +1,9 @@ -import { ArgumentsHost, Logger, WsExceptionFilter } from '@nestjs/common'; +import { + ArgumentsHost, + IntrinsicException, + Logger, + WsExceptionFilter, +} from '@nestjs/common'; import { isObject } from '@nestjs/common/utils/shared.utils'; import { MESSAGES } from '@nestjs/core/constants'; import { WsException } from '../errors/ws-exception'; @@ -46,7 +51,10 @@ export class BaseWsExceptionFilter message: MESSAGES.UNKNOWN_EXCEPTION_MESSAGE, }); - return BaseWsExceptionFilter.logger.error(exception); + if (!(exception instanceof IntrinsicException)) { + const logger = BaseWsExceptionFilter.logger; + logger.error(exception); + } } public isExceptionObject(err: any): err is Error {