diff --git a/packages/common/exceptions/http.exception.ts b/packages/common/exceptions/http.exception.ts index 8b21b9a392f..090c4ae7acf 100644 --- a/packages/common/exceptions/http.exception.ts +++ b/packages/common/exceptions/http.exception.ts @@ -9,6 +9,7 @@ export interface HttpExceptionOptions { /** original cause of the error */ cause?: unknown; description?: string; + errorCode?: string; } export interface DescriptionAndOptions { @@ -30,6 +31,7 @@ export class HttpException extends IntrinsicException { * 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; + public errorCode?: string; /** * Instantiate a plain HTTP Exception. @@ -73,6 +75,7 @@ export class HttpException extends IntrinsicException { this.initMessage(); this.initName(); this.initCause(); + this.initErrorCode(); } /** @@ -88,6 +91,12 @@ export class HttpException extends IntrinsicException { } } + public initErrorCode(): void { + if (this.options?.errorCode) { + this.errorCode = this.options.errorCode; + } + } + public initMessage() { if (isString(this.response)) { this.message = this.response; @@ -122,6 +131,12 @@ export class HttpException extends IntrinsicException { error: string, statusCode: number, ): HttpExceptionBody; + public static createBody( + message: HttpExceptionBodyMessage, + error: string, + statusCode: number, + errorCode?: string, + ): HttpExceptionBody; public static createBody>( custom: Body, ): Body; @@ -129,20 +144,29 @@ export class HttpException extends IntrinsicException { arg0: null | HttpExceptionBodyMessage | Body, arg1?: HttpExceptionBodyMessage | string, statusCode?: number, + errorCode?: string, ): HttpExceptionBody | Body { if (!arg0) { - return { + const body: HttpExceptionBody = { message: arg1!, statusCode: statusCode!, }; + if (errorCode) { + body.errorCode = errorCode; + } + return body; } if (isString(arg0) || Array.isArray(arg0) || isNumber(arg0)) { - return { + const body: HttpExceptionBody = { message: arg0, error: arg1 as string, statusCode: statusCode!, }; + if (errorCode) { + body.errorCode = errorCode; + } + return body; } return arg0; diff --git a/packages/common/interfaces/http/http-exception-body.interface.ts b/packages/common/interfaces/http/http-exception-body.interface.ts index b9f4732d622..9f12e4c549d 100644 --- a/packages/common/interfaces/http/http-exception-body.interface.ts +++ b/packages/common/interfaces/http/http-exception-body.interface.ts @@ -1,7 +1,8 @@ export type HttpExceptionBodyMessage = string | string[] | number; export interface HttpExceptionBody { + statusCode: number; message: HttpExceptionBodyMessage; error?: string; - statusCode: number; + errorCode?: string; } diff --git a/packages/common/test/exceptions/http.exception.spec.ts b/packages/common/test/exceptions/http.exception.spec.ts index 3bcc6d2aecb..08ea3263b5e 100644 --- a/packages/common/test/exceptions/http.exception.spec.ts +++ b/packages/common/test/exceptions/http.exception.spec.ts @@ -25,6 +25,7 @@ import { UnprocessableEntityException, UnsupportedMediaTypeException, } from '../../exceptions'; +import { HttpStatus } from '@nestjs/common'; describe('HttpException', () => { describe('getResponse', () => { @@ -268,4 +269,66 @@ describe('HttpException', () => { }); }); }); + + describe('when exception is created with a string and a description', () => { + it('should return a response with a message, error and status code', () => { + const exception = new HttpException('Forbidden', HttpStatus.FORBIDDEN); + expect(exception.getResponse()).to.deep.equal('Forbidden'); + }); + + it('should return a response with a message, error, status code and description', () => { + const exception = new HttpException('Forbidden', HttpStatus.FORBIDDEN, { + description: 'some description', + }); + expect(exception.getResponse()).to.deep.equal('Forbidden'); + }); + }); + + describe('when exception is created with a string and a cause', () => { + it('should set a cause', () => { + const error = new Error('An internal error cause'); + const exception = new HttpException( + 'Bad request', + HttpStatus.BAD_REQUEST, + { cause: error }, + ); + expect(exception.cause).to.equal(error); + }); + }); + + describe('when exception is created with an errorCode', () => { + it('should set an errorCode', () => { + const exception = new HttpException( + 'Bad request', + HttpStatus.BAD_REQUEST, + { + errorCode: 'BAD_REQUEST_CODE', + }, + ); + expect(exception.errorCode).to.equal('BAD_REQUEST_CODE'); + }); + + it('should be included in the response body when createBody is called', () => { + const body = HttpException.createBody( + 'Bad Request', + 'Error', + 400, + 'BAD_REQUEST_CODE', + ); + expect(body.errorCode).to.equal('BAD_REQUEST_CODE'); + }); + }); + + describe('when exception is thrown', () => { + it('should return a response with a status code and a message', () => { + const exception = new BadRequestException('error'); + const response = exception.getResponse(); + const message = { + statusCode: 400, + error: 'Bad Request', + message: 'error', + }; + expect(message).to.deep.equal(response); + }); + }); });