From ce2a2f59641b09df2a7804eac85dc5fc5ee91684 Mon Sep 17 00:00:00 2001 From: Karibash <40270352+Karibash@users.noreply.github.com> Date: Sun, 25 Feb 2024 19:07:33 +0900 Subject: [PATCH] feat(http-exception): Add a "cause" option to HTTPException (#2224) --- deno_dist/http-exception.ts | 5 ++++- src/http-exception.test.ts | 25 ++++++++++++++++++++++--- src/http-exception.ts | 5 ++++- tsconfig.json | 4 ++-- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/deno_dist/http-exception.ts b/deno_dist/http-exception.ts index 3a6e3da9..6b29559d 100644 --- a/deno_dist/http-exception.ts +++ b/deno_dist/http-exception.ts @@ -3,6 +3,7 @@ import type { StatusCode } from './utils/http-status.ts' type HTTPExceptionOptions = { res?: Response message?: string + cause?: unknown } /** @@ -26,11 +27,13 @@ type HTTPExceptionOptions = { export class HTTPException extends Error { readonly res?: Response readonly status: StatusCode + constructor(status: StatusCode = 500, options?: HTTPExceptionOptions) { - super(options?.message) + super(options?.message, { cause: options?.cause }) this.res = options?.res this.status = status } + getResponse(): Response { if (this.res) { return this.res diff --git a/src/http-exception.test.ts b/src/http-exception.test.ts index 8694e4b9..f77ecaf3 100644 --- a/src/http-exception.test.ts +++ b/src/http-exception.test.ts @@ -1,15 +1,34 @@ import { HTTPException } from './http-exception' -describe('HTTPFatalError', () => { - it('Should be 401 HTTP exception object', () => { +describe('HTTPException', () => { + it('Should be 401 HTTP exception object', async () => { // We should throw an exception if is not authorized // because next handlers should not be fired. const exception = new HTTPException(401, { message: 'Unauthorized', }) + const res = exception.getResponse() + + expect(res.status).toBe(401) + expect(await res.text()).toBe('Unauthorized') expect(exception.status).toBe(401) expect(exception.message).toBe('Unauthorized') + }) + + it('Should be accessible to the object causing the exception', async () => { + // We should pass the cause of the error to the cause option + // because it makes debugging easier. + const error = new Error('Server Error') + const exception = new HTTPException(500, { + message: 'Internal Server Error', + cause: error, + }) const res = exception.getResponse() - expect(res.status).toBe(401) + + expect(res.status).toBe(500) + expect(await res.text()).toBe('Internal Server Error') + expect(exception.status).toBe(500) + expect(exception.message).toBe('Internal Server Error') + expect(exception.cause).toBe(error) }) }) diff --git a/src/http-exception.ts b/src/http-exception.ts index ca40071f..b5761a64 100644 --- a/src/http-exception.ts +++ b/src/http-exception.ts @@ -3,6 +3,7 @@ import type { StatusCode } from './utils/http-status' type HTTPExceptionOptions = { res?: Response message?: string + cause?: unknown } /** @@ -26,11 +27,13 @@ type HTTPExceptionOptions = { export class HTTPException extends Error { readonly res?: Response readonly status: StatusCode + constructor(status: StatusCode = 500, options?: HTTPExceptionOptions) { - super(options?.message) + super(options?.message, { cause: options?.cause }) this.res = options?.res this.status = status } + getResponse(): Response { if (this.res) { return this.res diff --git a/tsconfig.json b/tsconfig.json index dd3f1602..a580d709 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "declaration": true, "moduleResolution": "Bundler", "outDir": "./dist", @@ -25,4 +25,4 @@ "src/**/*.test.ts", "src/**/*.test.tsx" ], -} \ No newline at end of file +}