Repository: nestjs/nest
Pull request #10460 (2022-10-25 21:15:17)

feat(common): add error options object
add error options object to HttpException constructor to allow use of error cause along with custom message.

## PR Checklist
Please check if your PR fulfills the following requirements:

- [x] The commit message follows our guidelines: https://github.com/nestjs/nest/blob/master/CONTRIBUTING.md
- [x] Tests for the changes have been added (for bug fixes / features)
- [x] Docs have been added / updated (for bug fixes / features)


## PR Type
What kind of change does this PR introduce?

<!-- Please check the one that applies to this PR using "x". -->
- [ ] Bugfix
- [x] Feature
- [ ] Code style update (formatting, local variables)
- [ ] Refactoring (no functional changes, no api changes)
- [ ] Build related changes
- [ ] CI related changes
- [ ] Other... Please describe:

## What is the current behavior?
We can only pass either a custom description or a cause error object.

Issue Number: #10392 


## What is the new behavior?
We can now use both custom messages and error cause with the following API:

```ts
const error = new HttpException('customDescription', 400, {
        cause: new Error(),
      });
```

## Does this PR introduce a breaking change?
- [ ] Yes
- [x] No

<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->


## Other information

We have yet to define what is the expected behavior when someone mistakenly passes both the first argument as an Error and also the `options` object with a cause. In that case, should we always consider the `cause` property or throw an error, @kamilmysliwiec ?


Patch:
diff --git a/packages/common/exceptions/bad-gateway.exception.ts b/packages/common/exceptions/bad-gateway.exception.ts
index 83ae75507..ba46421b5 100644
--- a/packages/common/exceptions/bad-gateway.exception.ts
+++ b/packages/common/exceptions/bad-gateway.exception.ts
@@ -1,5 +1,6 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { isString } from '../utils/shared.utils';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Bad Gateway* type errors.
@@ -18,7 +19,7 @@ export class BadGatewayException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 502.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 502.
@@ -31,12 +32,15 @@ export class BadGatewayException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Bad Gateway',
+    descriptionOrOptions: string | HttpExceptionOptions = 'Bad Gateway',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +48,7 @@ export class BadGatewayException extends HttpException {
         HttpStatus.BAD_GATEWAY,
       ),
       HttpStatus.BAD_GATEWAY,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/bad-request.exception.ts b/packages/common/exceptions/bad-request.exception.ts
index 3d93e229b..b9f04fe62 100644
--- a/packages/common/exceptions/bad-request.exception.ts
+++ b/packages/common/exceptions/bad-request.exception.ts
@@ -1,5 +1,6 @@
+import { isString } from 'class-validator';
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Bad Request* type errors.
@@ -18,7 +19,7 @@ export class BadRequestException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 400.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 400.
@@ -31,12 +32,15 @@ export class BadRequestException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Bad Request',
+    descriptionOrOptions: string | HttpExceptionOptions = 'Bad Request',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +48,7 @@ export class BadRequestException extends HttpException {
         HttpStatus.BAD_REQUEST,
       ),
       HttpStatus.BAD_REQUEST,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/conflict.exception.ts b/packages/common/exceptions/conflict.exception.ts
index 93322515e..f7810ffbe 100644
--- a/packages/common/exceptions/conflict.exception.ts
+++ b/packages/common/exceptions/conflict.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Conflict* type errors.
@@ -18,7 +18,7 @@ export class ConflictException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 409.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 409.
@@ -31,12 +31,19 @@ export class ConflictException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
-  constructor(objectOrError?: string | object | any, description = 'Conflict') {
+  constructor(
+    objectOrError?: string | object | any,
+    descriptionOrOptions: string | HttpExceptionOptions = 'Conflict',
+  ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(objectOrError, description, HttpStatus.CONFLICT),
       HttpStatus.CONFLICT,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/forbidden.exception.ts b/packages/common/exceptions/forbidden.exception.ts
index 2c10e7a2a..8079823d8 100644
--- a/packages/common/exceptions/forbidden.exception.ts
+++ b/packages/common/exceptions/forbidden.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Forbidden* type errors.
@@ -18,7 +18,7 @@ export class ForbiddenException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 403.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 403.
@@ -31,12 +31,15 @@ export class ForbiddenException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Forbidden',
+    descriptionOrOptions: string | HttpExceptionOptions = 'Forbidden',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +47,7 @@ export class ForbiddenException extends HttpException {
         HttpStatus.FORBIDDEN,
       ),
       HttpStatus.FORBIDDEN,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/gateway-timeout.exception.ts b/packages/common/exceptions/gateway-timeout.exception.ts
index e2d068518..6953f0cb2 100644
--- a/packages/common/exceptions/gateway-timeout.exception.ts
+++ b/packages/common/exceptions/gateway-timeout.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Gateway Timeout* type errors.
@@ -18,7 +18,7 @@ export class GatewayTimeoutException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 504.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 504.
@@ -31,12 +31,15 @@ export class GatewayTimeoutException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Gateway Timeout',
+    descriptionOrOptions: string | HttpExceptionOptions = 'Gateway Timeout',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +47,7 @@ export class GatewayTimeoutException extends HttpException {
         HttpStatus.GATEWAY_TIMEOUT,
       ),
       HttpStatus.GATEWAY_TIMEOUT,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/gone.exception.ts b/packages/common/exceptions/gone.exception.ts
index f319fe558..3e080906a 100644
--- a/packages/common/exceptions/gone.exception.ts
+++ b/packages/common/exceptions/gone.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Gone* type errors.
@@ -18,7 +18,7 @@ export class GoneException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 410.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 410.
@@ -31,12 +31,19 @@ export class GoneException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
-  constructor(objectOrError?: string | object | any, description = 'Gone') {
+  constructor(
+    objectOrError?: string | object | any,
+    descriptionOrOptions: string | HttpExceptionOptions = 'Gone',
+  ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(objectOrError, description, HttpStatus.GONE),
       HttpStatus.GONE,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/http-version-not-supported.exception.ts b/packages/common/exceptions/http-version-not-supported.exception.ts
index ded68714b..922d75ff0 100644
--- a/packages/common/exceptions/http-version-not-supported.exception.ts
+++ b/packages/common/exceptions/http-version-not-supported.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Http Version Not Supported* type errors.
@@ -18,7 +18,7 @@ export class HttpVersionNotSupportedException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 505.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 505.
@@ -31,12 +31,17 @@ export class HttpVersionNotSupportedException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'HTTP Version Not Supported',
+    descriptionOrOptions:
+      | string
+      | HttpExceptionOptions = 'HTTP Version Not Supported',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +49,7 @@ export class HttpVersionNotSupportedException extends HttpException {
         HttpStatus.HTTP_VERSION_NOT_SUPPORTED,
       ),
       HttpStatus.HTTP_VERSION_NOT_SUPPORTED,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/http.exception.ts b/packages/common/exceptions/http.exception.ts
index 540844298..bc166a8a1 100644
--- a/packages/common/exceptions/http.exception.ts
+++ b/packages/common/exceptions/http.exception.ts
@@ -1,5 +1,16 @@
+import { Logger } from '../services';
 import { isObject, isString } from '../utils/shared.utils';
 
+export interface HttpExceptionOptions {
+  cause?: Error;
+  description?: string;
+}
+
+export interface DescriptionAndOptions {
+  description?: string;
+  httpExceptionOptions?: HttpExceptionOptions;
+}
+
 /**
  * Defines the base Nest HTTP exception, which is handled by the default
  * Exceptions Handler.
@@ -13,12 +24,22 @@ export class HttpException extends Error {
    * Instantiate a plain HTTP Exception.
    *
    * @example
-   * `throw new HttpException()`
+   * throw new HttpException()
+   * throw new HttpException('message', HttpStatus.BAD_REQUEST)
+   * throw new HttpException({ reason: 'this can be a human readable reason' }, HttpStatus.BAD_REQUEST)
+   * throw new HttpException(new Error('Cause Error'), HttpStatus.BAD_REQUEST)
+   * throw new HttpException('custom message', HttpStatus.BAD_REQUEST, {
+   *  cause: new Error('Cause Error'),
+   * })
+   *
    *
    * @usageNotes
    * The constructor arguments define the response and the HTTP response status code.
-   * - The `response` argument (required) defines the JSON response body.
+   * - The `response` argument (required) defines the JSON response body. alternatively, it can also be
+   *  an error object that is used to define an error [cause](https://nodejs.org/en/blog/release/v16.9.0/#error-cause).
    * - The `status` argument (required) defines the HTTP Status Code.
+   * - The `options` argument (optional) defines additional error options. Currently, it supports the `cause` attribute,
+   *  and can be used as an alternative way to specify the error cause: `const error = new HttpException('description', 400, { cause: new Error() });`
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: the Http Status Code.
@@ -31,12 +52,14 @@ export class HttpException extends Error {
    * The `status` argument is required, and should be a valid HTTP status code.
    * Best practice is to use the `HttpStatus` enum imported from `nestjs/common`.
    *
-   * @param response string or object describing the error condition.
+   * @param response string, object describing the error condition or the error cause.
    * @param status HTTP response status code.
+   * @param options An object used to add an error cause.
    */
   constructor(
     private readonly response: string | Record<string, any>,
     private readonly status: number,
+    private readonly options?: HttpExceptionOptions,
   ) {
     super();
     this.initMessage();
@@ -53,8 +76,16 @@ export class HttpException extends Error {
    * - https://nodejs.org/en/blog/release/v16.9.0/#error-cause
    * - https://github.com/microsoft/TypeScript/issues/45167
    */
-  public initCause() {
+  public initCause(): void {
+    if (this.options?.cause) {
+      this.cause = this.options.cause;
+      return;
+    }
+
     if (this.response instanceof Error) {
+      Logger.warn(
+        'DEPRECATED! Passing the error cause as the first argument to HttpException constructor is deprecated. You should use the "options" parameter instead: new HttpException("message", 400, { cause: new Error("Some Error") }) ',
+      );
       this.cause = this.response;
     }
   }
@@ -87,15 +118,52 @@ export class HttpException extends Error {
   }
 
   public static createBody(
-    objectOrError: object | string,
+    objectOrErrorMessage: object | string,
     description?: string,
     statusCode?: number,
   ) {
-    if (!objectOrError) {
+    if (!objectOrErrorMessage) {
       return { statusCode, message: description };
     }
-    return isObject(objectOrError) && !Array.isArray(objectOrError)
-      ? objectOrError
-      : { statusCode, message: objectOrError, error: description };
+    return isObject(objectOrErrorMessage) &&
+      !Array.isArray(objectOrErrorMessage)
+      ? objectOrErrorMessage
+      : { statusCode, message: objectOrErrorMessage, error: description };
+  }
+
+  public static getDescriptionFrom(
+    descriptionOrOptions: string | HttpExceptionOptions,
+  ): string {
+    return isString(descriptionOrOptions)
+      ? descriptionOrOptions
+      : descriptionOrOptions?.description;
+  }
+
+  public static getHttpExceptionOptionsFrom(
+    descriptionOrOptions: string | HttpExceptionOptions,
+  ): HttpExceptionOptions {
+    return isString(descriptionOrOptions) ? {} : descriptionOrOptions;
+  }
+
+  /**
+   * Utility method used to extract the error description and httpExceptionOptions from the given argument.
+   * This is used by inheriting classes to correctly parse both options.
+   * @returns the error description and the httpExceptionOptions as an object.
+   */
+  public static extractDescriptionAndOptionsFrom(
+    descriptionOrOptions: string | HttpExceptionOptions,
+  ): DescriptionAndOptions {
+    const description = isString(descriptionOrOptions)
+      ? descriptionOrOptions
+      : descriptionOrOptions?.description;
+
+    const httpExceptionOptions = isString(descriptionOrOptions)
+      ? {}
+      : descriptionOrOptions;
+
+    return {
+      description,
+      httpExceptionOptions,
+    };
   }
 }
diff --git a/packages/common/exceptions/im-a-teapot.exception.ts b/packages/common/exceptions/im-a-teapot.exception.ts
index 4b345681e..76c67861e 100644
--- a/packages/common/exceptions/im-a-teapot.exception.ts
+++ b/packages/common/exceptions/im-a-teapot.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *ImATeapotException* type errors.
@@ -21,7 +21,7 @@ export class ImATeapotException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 418.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 418.
@@ -34,12 +34,15 @@ export class ImATeapotException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = `I'm a teapot`,
+    descriptionOrOptions: string | HttpExceptionOptions = `I'm a teapot`,
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -47,6 +50,7 @@ export class ImATeapotException extends HttpException {
         HttpStatus.I_AM_A_TEAPOT,
       ),
       HttpStatus.I_AM_A_TEAPOT,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/internal-server-error.exception.ts b/packages/common/exceptions/internal-server-error.exception.ts
index 673a2e7a2..c3393cf37 100644
--- a/packages/common/exceptions/internal-server-error.exception.ts
+++ b/packages/common/exceptions/internal-server-error.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Internal Server Error* type errors.
@@ -18,7 +18,7 @@ export class InternalServerErrorException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 500.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 500.
@@ -31,12 +31,17 @@ export class InternalServerErrorException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Internal Server Error',
+    descriptionOrOptions:
+      | string
+      | HttpExceptionOptions = 'Internal Server Error',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +49,7 @@ export class InternalServerErrorException extends HttpException {
         HttpStatus.INTERNAL_SERVER_ERROR,
       ),
       HttpStatus.INTERNAL_SERVER_ERROR,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/method-not-allowed.exception.ts b/packages/common/exceptions/method-not-allowed.exception.ts
index f44ad305b..9cf0d8381 100644
--- a/packages/common/exceptions/method-not-allowed.exception.ts
+++ b/packages/common/exceptions/method-not-allowed.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Method Not Allowed* type errors.
@@ -18,7 +18,7 @@ export class MethodNotAllowedException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 405.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 405.
@@ -31,12 +31,15 @@ export class MethodNotAllowedException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Method Not Allowed',
+    descriptionOrOptions: string | HttpExceptionOptions = 'Method Not Allowed',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +47,7 @@ export class MethodNotAllowedException extends HttpException {
         HttpStatus.METHOD_NOT_ALLOWED,
       ),
       HttpStatus.METHOD_NOT_ALLOWED,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/misdirected.exception.ts b/packages/common/exceptions/misdirected.exception.ts
index 5fa2f082c..547ab4431 100644
--- a/packages/common/exceptions/misdirected.exception.ts
+++ b/packages/common/exceptions/misdirected.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Misdirected* type errors.
@@ -18,7 +18,7 @@ export class MisdirectedException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 421.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 421.
@@ -31,12 +31,15 @@ export class MisdirectedException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Misdirected',
+    descriptionOrOptions: string | HttpExceptionOptions = 'Misdirected',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +47,7 @@ export class MisdirectedException extends HttpException {
         HttpStatus.MISDIRECTED,
       ),
       HttpStatus.MISDIRECTED,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/not-acceptable.exception.ts b/packages/common/exceptions/not-acceptable.exception.ts
index 18e71156c..548b2dd79 100644
--- a/packages/common/exceptions/not-acceptable.exception.ts
+++ b/packages/common/exceptions/not-acceptable.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Not Acceptable* type errors.
@@ -18,7 +18,7 @@ export class NotAcceptableException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 406.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 406.
@@ -31,12 +31,15 @@ export class NotAcceptableException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Not Acceptable',
+    descriptionOrOptions: string | HttpExceptionOptions = 'Not Acceptable',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +47,7 @@ export class NotAcceptableException extends HttpException {
         HttpStatus.NOT_ACCEPTABLE,
       ),
       HttpStatus.NOT_ACCEPTABLE,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/not-found.exception.ts b/packages/common/exceptions/not-found.exception.ts
index a8ab1491a..b44a744e0 100644
--- a/packages/common/exceptions/not-found.exception.ts
+++ b/packages/common/exceptions/not-found.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Not Found* type errors.
@@ -18,7 +18,7 @@ export class NotFoundException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 404.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 404.
@@ -31,12 +31,15 @@ export class NotFoundException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Not Found',
+    descriptionOrOptions: string | HttpExceptionOptions = 'Not Found',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +47,7 @@ export class NotFoundException extends HttpException {
         HttpStatus.NOT_FOUND,
       ),
       HttpStatus.NOT_FOUND,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/not-implemented.exception.ts b/packages/common/exceptions/not-implemented.exception.ts
index 0576406fc..6f6912649 100644
--- a/packages/common/exceptions/not-implemented.exception.ts
+++ b/packages/common/exceptions/not-implemented.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Not Implemented* type errors.
@@ -18,7 +18,7 @@ export class NotImplementedException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 501.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 501.
@@ -30,13 +30,16 @@ export class NotImplementedException extends HttpException {
    * entire JSON response body, pass an object instead. Nest will serialize the object
    * and return it as the JSON response body.
    *
-   * @param description string or object describing the error condition.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    * @param error a short description of the HTTP error.
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Not Implemented',
+    descriptionOrOptions: string | HttpExceptionOptions = 'Not Implemented',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +47,7 @@ export class NotImplementedException extends HttpException {
         HttpStatus.NOT_IMPLEMENTED,
       ),
       HttpStatus.NOT_IMPLEMENTED,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/payload-too-large.exception.ts b/packages/common/exceptions/payload-too-large.exception.ts
index 3f967f834..73de7d1f2 100644
--- a/packages/common/exceptions/payload-too-large.exception.ts
+++ b/packages/common/exceptions/payload-too-large.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Payload Too Large* type errors.
@@ -18,7 +18,7 @@ export class PayloadTooLargeException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 413.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 413.
@@ -31,12 +31,15 @@ export class PayloadTooLargeException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Payload Too Large',
+    descriptionOrOptions: string | HttpExceptionOptions = 'Payload Too Large',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +47,7 @@ export class PayloadTooLargeException extends HttpException {
         HttpStatus.PAYLOAD_TOO_LARGE,
       ),
       HttpStatus.PAYLOAD_TOO_LARGE,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/precondition-failed.exception.ts b/packages/common/exceptions/precondition-failed.exception.ts
index 6e8456396..d03da41d0 100644
--- a/packages/common/exceptions/precondition-failed.exception.ts
+++ b/packages/common/exceptions/precondition-failed.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Precondition Failed* type errors.
@@ -18,7 +18,7 @@ export class PreconditionFailedException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 412.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 412.
@@ -31,12 +31,15 @@ export class PreconditionFailedException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Precondition Failed',
+    descriptionOrOptions: string | HttpExceptionOptions = 'Precondition Failed',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +47,7 @@ export class PreconditionFailedException extends HttpException {
         HttpStatus.PRECONDITION_FAILED,
       ),
       HttpStatus.PRECONDITION_FAILED,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/request-timeout.exception.ts b/packages/common/exceptions/request-timeout.exception.ts
index 8521e290f..d91c3cfd1 100644
--- a/packages/common/exceptions/request-timeout.exception.ts
+++ b/packages/common/exceptions/request-timeout.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Request Timeout* type errors.
@@ -18,7 +18,7 @@ export class RequestTimeoutException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 408.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 408.
@@ -31,12 +31,15 @@ export class RequestTimeoutException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Request Timeout',
+    descriptionOrOptions: string | HttpExceptionOptions = 'Request Timeout',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +47,7 @@ export class RequestTimeoutException extends HttpException {
         HttpStatus.REQUEST_TIMEOUT,
       ),
       HttpStatus.REQUEST_TIMEOUT,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/service-unavailable.exception.ts b/packages/common/exceptions/service-unavailable.exception.ts
index b7721322f..2d1c6bd03 100644
--- a/packages/common/exceptions/service-unavailable.exception.ts
+++ b/packages/common/exceptions/service-unavailable.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Service Unavailable* type errors.
@@ -18,7 +18,7 @@ export class ServiceUnavailableException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 503.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 503.
@@ -31,12 +31,15 @@ export class ServiceUnavailableException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Service Unavailable',
+    descriptionOrOptions: string | HttpExceptionOptions = 'Service Unavailable',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +47,7 @@ export class ServiceUnavailableException extends HttpException {
         HttpStatus.SERVICE_UNAVAILABLE,
       ),
       HttpStatus.SERVICE_UNAVAILABLE,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/unauthorized.exception.ts b/packages/common/exceptions/unauthorized.exception.ts
index 1791316c6..b85fa847e 100644
--- a/packages/common/exceptions/unauthorized.exception.ts
+++ b/packages/common/exceptions/unauthorized.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Unauthorized* type errors.
@@ -18,7 +18,7 @@ export class UnauthorizedException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 401.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 401.
@@ -31,12 +31,15 @@ export class UnauthorizedException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Unauthorized',
+    descriptionOrOptions: string | HttpExceptionOptions = 'Unauthorized',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +47,7 @@ export class UnauthorizedException extends HttpException {
         HttpStatus.UNAUTHORIZED,
       ),
       HttpStatus.UNAUTHORIZED,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/unprocessable-entity.exception.ts b/packages/common/exceptions/unprocessable-entity.exception.ts
index b1cf34b77..a4e012cac 100644
--- a/packages/common/exceptions/unprocessable-entity.exception.ts
+++ b/packages/common/exceptions/unprocessable-entity.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Unprocessable Entity* type errors.
@@ -18,7 +18,7 @@ export class UnprocessableEntityException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 422.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 422.
@@ -31,12 +31,17 @@ export class UnprocessableEntityException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Unprocessable Entity',
+    descriptionOrOptions:
+      | string
+      | HttpExceptionOptions = 'Unprocessable Entity',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +49,7 @@ export class UnprocessableEntityException extends HttpException {
         HttpStatus.UNPROCESSABLE_ENTITY,
       ),
       HttpStatus.UNPROCESSABLE_ENTITY,
+      httpExceptionOptions,
     );
   }
 }
diff --git a/packages/common/exceptions/unsupported-media-type.exception.ts b/packages/common/exceptions/unsupported-media-type.exception.ts
index eaeab69a9..fb8a0e1df 100644
--- a/packages/common/exceptions/unsupported-media-type.exception.ts
+++ b/packages/common/exceptions/unsupported-media-type.exception.ts
@@ -1,5 +1,5 @@
 import { HttpStatus } from '../enums/http-status.enum';
-import { HttpException } from './http.exception';
+import { HttpException, HttpExceptionOptions } from './http.exception';
 
 /**
  * Defines an HTTP exception for *Unsupported Media Type* type errors.
@@ -18,7 +18,7 @@ export class UnsupportedMediaTypeException extends HttpException {
    * @usageNotes
    * The HTTP response status code will be 415.
    * - The `objectOrError` argument defines the JSON response body or the message string.
-   * - The `description` argument contains a short description of the HTTP error.
+   * - The `descriptionOrOptions` argument contains either a short description of the HTTP error or an options object used to provide an underlying error cause.
    *
    * By default, the JSON response body contains two properties:
    * - `statusCode`: this will be the value 415.
@@ -31,12 +31,17 @@ export class UnsupportedMediaTypeException extends HttpException {
    * and return it as the JSON response body.
    *
    * @param objectOrError string or object describing the error condition.
-   * @param description a short description of the HTTP error.
+   * @param descriptionOrOptions either a short description of the HTTP error or an options object used to provide an underlying error cause
    */
   constructor(
     objectOrError?: string | object | any,
-    description = 'Unsupported Media Type',
+    descriptionOrOptions:
+      | string
+      | HttpExceptionOptions = 'Unsupported Media Type',
   ) {
+    const { description, httpExceptionOptions } =
+      HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
+
     super(
       HttpException.createBody(
         objectOrError,
@@ -44,6 +49,7 @@ export class UnsupportedMediaTypeException extends HttpException {
         HttpStatus.UNSUPPORTED_MEDIA_TYPE,
       ),
       HttpStatus.UNSUPPORTED_MEDIA_TYPE,
+      httpExceptionOptions,
     );
   }
 }


Test patch:
diff --git a/packages/common/test/exceptions/http.exception.spec.ts b/packages/common/test/exceptions/http.exception.spec.ts
index a880c1bfc..0b7f21ed7 100644
--- a/packages/common/test/exceptions/http.exception.spec.ts
+++ b/packages/common/test/exceptions/http.exception.spec.ts
@@ -1,56 +1,145 @@
+import { Type } from '../../../common';
 import { expect } from 'chai';
 import {
+  BadGatewayException,
   BadRequestException,
+  ConflictException,
+  ForbiddenException,
+  GatewayTimeoutException,
+  GoneException,
   HttpException,
+  HttpVersionNotSupportedException,
+  ImATeapotException,
+  InternalServerErrorException,
+  MethodNotAllowedException,
+  MisdirectedException,
+  NotAcceptableException,
   NotFoundException,
+  NotImplementedException,
+  PayloadTooLargeException,
+  PreconditionFailedException,
+  RequestTimeoutException,
+  ServiceUnavailableException,
+  UnauthorizedException,
+  UnprocessableEntityException,
+  UnsupportedMediaTypeException,
 } from '../../exceptions';
 
 describe('HttpException', () => {
-  it('should return a response as a string when input is a string', () => {
-    const message = 'My error message';
-    expect(new HttpException(message, 404).getResponse()).to.be.eql(
-      'My error message',
-    );
-  });
+  describe('getResponse', () => {
+    it('should return a response as a string when input is a string', () => {
+      const message = 'My error message';
+      expect(new HttpException(message, 404).getResponse()).to.be.eql(
+        'My error message',
+      );
+    });
 
-  it('should return a response as an object when input is an object', () => {
-    const message = {
-      msg: 'My error message',
-      reason: 'this can be a human readable reason',
-      anything: 'else',
-    };
-    expect(new HttpException(message, 404).getResponse()).to.be.eql(message);
-  });
+    it('should return a response as an object when input is an object', () => {
+      const message = {
+        msg: 'My error message',
+        reason: 'this can be a human readable reason',
+        anything: 'else',
+      };
+      expect(new HttpException(message, 404).getResponse()).to.be.eql(message);
+    });
 
-  it('should return a message from a built-in exception as an object', () => {
-    const message = 'My error message';
-    expect(new BadRequestException(message).getResponse()).to.be.eql({
-      statusCode: 400,
-      error: 'Bad Request',
-      message: 'My error message',
+    it('should return a message from a built-in exception as an object', () => {
+      const message = 'My error message';
+      expect(new BadRequestException(message).getResponse()).to.be.eql({
+        statusCode: 400,
+        error: 'Bad Request',
+        message: 'My error message',
+      });
     });
-  });
 
-  it('should return an object even when the message is undefined', () => {
-    expect(new BadRequestException().getResponse()).to.be.eql({
-      statusCode: 400,
-      message: 'Bad Request',
+    it('should return an object even when the message is undefined', () => {
+      expect(new BadRequestException().getResponse()).to.be.eql({
+        statusCode: 400,
+        message: 'Bad Request',
+      });
     });
   });
 
-  it('should return a status code', () => {
-    expect(new BadRequestException().getStatus()).to.be.eql(400);
-    expect(new NotFoundException().getStatus()).to.be.eql(404);
-  });
+  describe('built-in exceptions', () => {
+    describe('getStatus', () => {
+      it('should return given status code', () => {
+        const testCases: [Type<HttpException>, number][] = [
+          [BadRequestException, 400],
+          [UnauthorizedException, 401],
+          [ForbiddenException, 403],
+          [NotFoundException, 404],
+          [MethodNotAllowedException, 405],
+          [NotAcceptableException, 406],
+          [RequestTimeoutException, 408],
+          [ConflictException, 409],
+          [GoneException, 410],
+          [PreconditionFailedException, 412],
+          [PayloadTooLargeException, 413],
+          [UnsupportedMediaTypeException, 415],
+          [ImATeapotException, 418],
+          [MisdirectedException, 421],
+          [UnprocessableEntityException, 422],
+          [InternalServerErrorException, 500],
+          [NotImplementedException, 501],
+          [BadGatewayException, 502],
+          [ServiceUnavailableException, 503],
+          [GatewayTimeoutException, 504],
+          [HttpVersionNotSupportedException, 505],
+        ];
 
-  it('should return a response', () => {
-    expect(new BadRequestException().getResponse()).to.be.eql({
-      message: 'Bad Request',
-      statusCode: 400,
+        testCases.forEach(([ExceptionClass, expectedStatus]) => {
+          expect(new ExceptionClass().getStatus()).to.be.eql(expectedStatus);
+        });
+      });
     });
-    expect(new NotFoundException().getResponse()).to.be.eql({
-      message: 'Not Found',
-      statusCode: 404,
+
+    describe('getResponse', () => {
+      it('should return a response with default message and status code', () => {
+        const testCases: [Type<HttpException>, number, string][] = [
+          [BadRequestException, 400, 'Bad Request'],
+          [UnauthorizedException, 401, 'Unauthorized'],
+          [ForbiddenException, 403, 'Forbidden'],
+          [NotFoundException, 404, 'Not Found'],
+          [MethodNotAllowedException, 405, 'Method Not Allowed'],
+          [NotAcceptableException, 406, 'Not Acceptable'],
+          [RequestTimeoutException, 408, 'Request Timeout'],
+          [ConflictException, 409, 'Conflict'],
+          [GoneException, 410, 'Gone'],
+          [PreconditionFailedException, 412, 'Precondition Failed'],
+          [PayloadTooLargeException, 413, 'Payload Too Large'],
+          [UnsupportedMediaTypeException, 415, 'Unsupported Media Type'],
+          [ImATeapotException, 418, "I'm a teapot"],
+          [MisdirectedException, 421, 'Misdirected'],
+          [UnprocessableEntityException, 422, 'Unprocessable Entity'],
+          [InternalServerErrorException, 500, 'Internal Server Error'],
+          [NotImplementedException, 501, 'Not Implemented'],
+          [BadGatewayException, 502, 'Bad Gateway'],
+          [ServiceUnavailableException, 503, 'Service Unavailable'],
+          [GatewayTimeoutException, 504, 'Gateway Timeout'],
+          [HttpVersionNotSupportedException, 505, 'HTTP Version Not Supported'],
+        ];
+
+        testCases.forEach(
+          ([ExceptionClass, expectedStatus, expectedMessage]) => {
+            expect(new ExceptionClass().getResponse()).to.be.eql({
+              message: expectedMessage,
+              statusCode: expectedStatus,
+            });
+          },
+        );
+      });
+
+      it('should return a response with an "error" attribute when description was provided as the "option" object', () => {
+        const badRequestError = new BadRequestException('ErrorMessage', {
+          description: 'Some error description',
+        });
+
+        expect(badRequestError.getResponse()).to.be.eql({
+          message: 'ErrorMessage',
+          error: 'Some error description',
+          statusCode: 400,
+        });
+      });
     });
   });
 
@@ -59,31 +148,28 @@ describe('HttpException', () => {
     expect(error instanceof Error).to.be.true;
   });
 
-  it('should be serializable', () => {
-    const message = 'Some Error';
-    const error = new HttpException(message, 400);
-    expect(`${error}`).to.be.eql(`HttpException: ${message}`);
-  });
+  describe('when serializing', () => {
+    describe('and "response" parameter is a string', () => {
+      it('should concatenate HttpException with the given message', () => {
+        const responseAsString = 'Some Error';
+        const error = new HttpException(responseAsString, 400);
+        expect(`${error}`).to.be.eql(`HttpException: ${responseAsString}`);
+        expect(`${error}`.includes('[object Object]')).to.not.be.true;
+      });
+    });
 
-  describe('when "response" is an object', () => {
-    it('should use default message', () => {
-      const obj = { foo: 'bar' };
-      const error = new HttpException(obj, 400);
-      const badRequestError = new BadRequestException(obj);
+    describe('and "response" parameter is an object', () => {
+      it('should use default message', () => {
+        const responseAsObject = { foo: 'bar' };
+        const error = new HttpException(responseAsObject, 400);
+        const badRequestError = new BadRequestException(responseAsObject);
 
-      expect(`${error}`).to.be.eql(`HttpException: Http Exception`);
-      expect(`${badRequestError}`).to.be.eql(
-        `BadRequestException: Bad Request Exception`,
-      );
-      expect(`${error}`.includes('[object Object]')).to.not.be.true;
-      expect(`${badRequestError}`.includes('[object Object]')).to.not.be.true;
-    });
-    describe('otherwise', () => {
-      it('should concat strings', () => {
-        const test = 'test message';
-        const error = new HttpException(test, 400);
-        expect(`${error}`).to.be.eql(`HttpException: ${test}`);
+        expect(`${error}`).to.be.eql(`HttpException: Http Exception`);
+        expect(`${badRequestError}`).to.be.eql(
+          `BadRequestException: Bad Request Exception`,
+        );
         expect(`${error}`.includes('[object Object]')).to.not.be.true;
+        expect(`${badRequestError}`.includes('[object Object]')).to.not.be.true;
       });
     });
   });
@@ -131,6 +217,9 @@ describe('HttpException', () => {
   });
 
   describe('initCause', () => {
+    const errorCause = new Error('An internal error cause');
+    const customDescription = 'custom description';
+
     it('configures a cause when message is an instance of error', () => {
       const message = new Error('Some Error');
       const error = new HttpException(message, 400);
@@ -139,5 +228,52 @@ describe('HttpException', () => {
 
       expect(cause).to.be.eql(message);
     });
+
+    it('configures a cause when message is a string and the options object is passed', () => {
+      const error = new HttpException(customDescription, 400, {
+        cause: errorCause,
+      });
+
+      expect(`${error}`).to.be.eql(`HttpException: ${customDescription}`);
+      const { cause } = error;
+
+      expect(cause).to.be.eql(errorCause);
+    });
+
+    it('configures a cause when using a bult-in exception with options', () => {
+      const builtInErrorClasses = [
+        BadGatewayException,
+        BadRequestException,
+        ConflictException,
+        ForbiddenException,
+        GatewayTimeoutException,
+        GoneException,
+        HttpVersionNotSupportedException,
+        ImATeapotException,
+        InternalServerErrorException,
+        MethodNotAllowedException,
+        MisdirectedException,
+        NotAcceptableException,
+        NotFoundException,
+        NotImplementedException,
+        PayloadTooLargeException,
+        PreconditionFailedException,
+        RequestTimeoutException,
+        ServiceUnavailableException,
+        UnauthorizedException,
+        UnprocessableEntityException,
+        UnsupportedMediaTypeException,
+      ];
+
+      builtInErrorClasses.forEach(ExceptionClass => {
+        const error = new ExceptionClass(customDescription, {
+          cause: errorCause,
+        });
+
+        const { cause } = error;
+
+        expect(cause).to.be.eql(errorCause);
+      });
+    });
   });
 });