From e989d06d654ee8c35f34b3dbd51186c350643fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20Bou=C3=A7as?= Date: Wed, 3 Apr 2024 10:59:52 +0100 Subject: [PATCH 1/3] feat: show details in error message --- src/headers.ts | 1 + src/main.test.ts | 7 ++++--- src/util.ts | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/headers.ts b/src/headers.ts index f7e85267..5222ca2a 100644 --- a/src/headers.ts +++ b/src/headers.ts @@ -1 +1,2 @@ +export const NF_ERROR = 'x-nf-error' export const NF_REQUEST_ID = 'x-nf-request-id' diff --git a/src/main.test.ts b/src/main.test.ts index 133e6f3d..0860adbe 100644 --- a/src/main.test.ts +++ b/src/main.test.ts @@ -8,7 +8,7 @@ import { MockFetch } from '../test/mock_fetch.js' import { base64Encode, streamToString } from '../test/util.js' import { MissingBlobsEnvironmentError } from './environment.js' -import { NF_REQUEST_ID } from './headers.js' +import { NF_ERROR, NF_REQUEST_ID } from './headers.js' import { getDeployStore, getStore, setEnvironmentContext } from './main.js' import { base64Decode } from './util.js' @@ -271,9 +271,10 @@ describe('get', () => { }) test('Throws when an edge URL returns a non-200 status code', async () => { + const errorDetails = 'Missing authorization header' const mockStore = new MockFetch().get({ headers: { authorization: `Bearer ${edgeToken}` }, - response: new Response(null, { status: 401 }), + response: new Response(null, { headers: { [NF_ERROR]: errorDetails }, status: 401 }), url: `${edgeURL}/${siteID}/site:production/${key}`, }) @@ -287,7 +288,7 @@ describe('get', () => { }) await expect(async () => await blobs.get(key)).rejects.toThrowError( - `Netlify Blobs has generated an internal error: 401 response`, + `Netlify Blobs has generated an internal error: ${errorDetails}`, ) expect(mockStore.fulfilled).toBeTruthy() diff --git a/src/util.ts b/src/util.ts index 8b1742e4..5a1be905 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,8 +1,10 @@ -import { NF_REQUEST_ID } from './headers.ts' +import { NF_ERROR, NF_REQUEST_ID } from './headers.ts' export class BlobsInternalError extends Error { constructor(res: Response) { - let message = `Netlify Blobs has generated an internal error: ${res.status} response` + const details = res.headers.get(NF_ERROR) ?? `${res.status} response` + + let message = `Netlify Blobs has generated an internal error: ${details}` if (res.headers.has(NF_REQUEST_ID)) { message += ` (ID: ${res.headers.get(NF_REQUEST_ID)})` From 3c036fc710abd7549efcb6c455443cd1e3ad1c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20Bou=C3=A7as?= Date: Wed, 3 Apr 2024 11:07:53 +0100 Subject: [PATCH 2/3] feat: add details to error message --- src/main.test.ts | 14 +++++++------- src/server.test.ts | 2 +- src/util.ts | 8 +++----- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/main.test.ts b/src/main.test.ts index 0860adbe..0882ebf7 100644 --- a/src/main.test.ts +++ b/src/main.test.ts @@ -135,7 +135,7 @@ describe('get', () => { }) expect(async () => await blobs.get(key)).rejects.toThrowError( - `Netlify Blobs has generated an internal error: 401 response (ID: ${mockRequestID})`, + `Netlify Blobs has generated an internal error (401 status code, ID: ${mockRequestID})`, ) expect(mockStore.fulfilled).toBeTruthy() }) @@ -161,7 +161,7 @@ describe('get', () => { }) await expect(async () => await blobs.get(key)).rejects.toThrowError( - `Netlify Blobs has generated an internal error: 401 response`, + `Netlify Blobs has generated an internal error (401 status code)`, ) expect(mockStore.fulfilled).toBeTruthy() @@ -288,7 +288,7 @@ describe('get', () => { }) await expect(async () => await blobs.get(key)).rejects.toThrowError( - `Netlify Blobs has generated an internal error: ${errorDetails}`, + `Netlify Blobs has generated an internal error (${errorDetails})`, ) expect(mockStore.fulfilled).toBeTruthy() @@ -819,7 +819,7 @@ describe('set', () => { }) expect(async () => await blobs.set(key, 'value')).rejects.toThrowError( - `Netlify Blobs has generated an internal error: 401 response`, + `Netlify Blobs has generated an internal error (401 status code)`, ) expect(mockStore.fulfilled).toBeTruthy() }) @@ -947,7 +947,7 @@ describe('set', () => { }) await expect(async () => await blobs.set(key, value)).rejects.toThrowError( - `Netlify Blobs has generated an internal error: 401 response`, + `Netlify Blobs has generated an internal error (401 status code)`, ) expect(mockStore.fulfilled).toBeTruthy() @@ -1170,7 +1170,7 @@ describe('delete', () => { }) await expect(async () => await blobs.delete(key)).rejects.toThrowError( - `Netlify Blobs has generated an internal error: 401 response`, + `Netlify Blobs has generated an internal error (401 status code)`, ) expect(mockStore.fulfilled).toBeTruthy() }) @@ -1236,7 +1236,7 @@ describe('delete', () => { }) await expect(async () => await blobs.delete(key)).rejects.toThrowError( - `Netlify Blobs has generated an internal error: 401 response`, + `Netlify Blobs has generated an internal error (401 status code)`, ) expect(mockStore.fulfilled).toBeTruthy() diff --git a/src/server.test.ts b/src/server.test.ts index f91d44eb..512c5591 100644 --- a/src/server.test.ts +++ b/src/server.test.ts @@ -196,7 +196,7 @@ test('If a token is set, rejects any requests with an invalid `authorization` he }) await expect(async () => await blobs.get('some-key')).rejects.toThrowError( - 'Netlify Blobs has generated an internal error: 403 response', + 'Netlify Blobs has generated an internal error (403 status code)', ) await server.stop() diff --git a/src/util.ts b/src/util.ts index 5a1be905..ed5fe502 100644 --- a/src/util.ts +++ b/src/util.ts @@ -2,15 +2,13 @@ import { NF_ERROR, NF_REQUEST_ID } from './headers.ts' export class BlobsInternalError extends Error { constructor(res: Response) { - const details = res.headers.get(NF_ERROR) ?? `${res.status} response` - - let message = `Netlify Blobs has generated an internal error: ${details}` + let details = res.headers.get(NF_ERROR) || `${res.status} status code` if (res.headers.has(NF_REQUEST_ID)) { - message += ` (ID: ${res.headers.get(NF_REQUEST_ID)})` + details += `, ID: ${res.headers.get(NF_REQUEST_ID)}` } - super(message) + super(`Netlify Blobs has generated an internal error (${details})`) this.name = 'BlobsInternalError' } From 0b269eeb92a83e5580509db4f33d5d3d807ebd14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20Bou=C3=A7as?= Date: Wed, 3 Apr 2024 11:13:10 +0100 Subject: [PATCH 3/3] chore: update test --- src/main.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.test.ts b/src/main.test.ts index 0882ebf7..2f0c677e 100644 --- a/src/main.test.ts +++ b/src/main.test.ts @@ -271,7 +271,7 @@ describe('get', () => { }) test('Throws when an edge URL returns a non-200 status code', async () => { - const errorDetails = 'Missing authorization header' + const errorDetails = 'Failed to decode token: Token expired' const mockStore = new MockFetch().get({ headers: { authorization: `Bearer ${edgeToken}` }, response: new Response(null, { headers: { [NF_ERROR]: errorDetails }, status: 401 }),