Skip to content

Commit b560051

Browse files
feat: add request ID to error messages (#165)
1 parent fe7d899 commit b560051

File tree

5 files changed

+24
-12
lines changed

5 files changed

+24
-12
lines changed

src/client.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { EnvironmentContext, getEnvironmentContext, MissingBlobsEnvironmentError
33
import { encodeMetadata, Metadata, METADATA_HEADER_EXTERNAL, METADATA_HEADER_INTERNAL } from './metadata.ts'
44
import { fetchAndRetry } from './retry.ts'
55
import { BlobInput, Fetcher, HTTPMethod } from './types.ts'
6+
import { BlobsInternalError } from './util.ts'
67

78
export const SIGNED_URL_ACCEPT_HEADER = 'application/json;type=signed-url'
89

@@ -156,7 +157,7 @@ export class Client {
156157
})
157158

158159
if (res.status !== 200) {
159-
throw new Error(`Netlify Blobs has generated an internal error: ${res.status} response`)
160+
throw new BlobsInternalError(res)
160161
}
161162

162163
const { url: signedURL } = await res.json()

src/headers.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const NF_REQUEST_ID = 'x-nf-request-id'

src/main.test.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { MockFetch } from '../test/mock_fetch.js'
88
import { base64Encode, streamToString } from '../test/util.js'
99

1010
import { MissingBlobsEnvironmentError } from './environment.js'
11+
import { NF_REQUEST_ID } from './headers.js'
1112
import { getDeployStore, getStore, setEnvironmentContext } from './main.js'
1213
import { base64Decode } from './util.js'
1314

@@ -118,9 +119,10 @@ describe('get', () => {
118119
})
119120

120121
test('Throws when the API returns a non-200 status code', async () => {
122+
const mockRequestID = '123456789'
121123
const mockStore = new MockFetch().get({
122124
headers: { accept: 'application/json;type=signed-url', authorization: `Bearer ${apiToken}` },
123-
response: new Response(null, { status: 401 }),
125+
response: new Response(null, { headers: { [NF_REQUEST_ID]: mockRequestID }, status: 401 }),
124126
url: `https://api.netlify.com/api/v1/blobs/${siteID}/site:production/${key}`,
125127
})
126128

@@ -133,7 +135,7 @@ describe('get', () => {
133135
})
134136

135137
expect(async () => await blobs.get(key)).rejects.toThrowError(
136-
`Netlify Blobs has generated an internal error: 401 response`,
138+
`Netlify Blobs has generated an internal error: 401 response (ID: ${mockRequestID})`,
137139
)
138140
expect(mockStore.fulfilled).toBeTruthy()
139141
})

src/store.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export class Store {
9292
const res = await this.client.makeRequest({ key, method: HTTPMethod.DELETE, storeName: this.name })
9393

9494
if (![200, 204, 404].includes(res.status)) {
95-
throw new BlobsInternalError(res.status)
95+
throw new BlobsInternalError(res)
9696
}
9797
}
9898

@@ -116,7 +116,7 @@ export class Store {
116116
}
117117

118118
if (res.status !== 200) {
119-
throw new BlobsInternalError(res.status)
119+
throw new BlobsInternalError(res)
120120
}
121121

122122
if (type === undefined || type === 'text') {
@@ -139,7 +139,7 @@ export class Store {
139139
return res.body
140140
}
141141

142-
throw new BlobsInternalError(res.status)
142+
throw new BlobsInternalError(res)
143143
}
144144

145145
async getMetadata(key: string, { consistency }: { consistency?: ConsistencyMode } = {}) {
@@ -150,7 +150,7 @@ export class Store {
150150
}
151151

152152
if (res.status !== 200 && res.status !== 304) {
153-
throw new BlobsInternalError(res.status)
153+
throw new BlobsInternalError(res)
154154
}
155155

156156
const etag = res?.headers.get('etag') ?? undefined
@@ -221,7 +221,7 @@ export class Store {
221221
}
222222

223223
if (res.status !== 200 && res.status !== 304) {
224-
throw new BlobsInternalError(res.status)
224+
throw new BlobsInternalError(res)
225225
}
226226

227227
const responseETag = res?.headers.get('etag') ?? undefined
@@ -293,7 +293,7 @@ export class Store {
293293
})
294294

295295
if (res.status !== 200) {
296-
throw new BlobsInternalError(res.status)
296+
throw new BlobsInternalError(res)
297297
}
298298
}
299299

@@ -315,7 +315,7 @@ export class Store {
315315
})
316316

317317
if (res.status !== 200) {
318-
throw new BlobsInternalError(res.status)
318+
throw new BlobsInternalError(res)
319319
}
320320
}
321321

src/util.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1+
import { NF_REQUEST_ID } from './headers.ts'
2+
13
export class BlobsInternalError extends Error {
2-
constructor(statusCode: number) {
3-
super(`Netlify Blobs has generated an internal error: ${statusCode} response`)
4+
constructor(res: Response) {
5+
let message = `Netlify Blobs has generated an internal error: ${res.status} response`
6+
7+
if (res.headers.has(NF_REQUEST_ID)) {
8+
message += ` (ID: ${res.headers.get(NF_REQUEST_ID)})`
9+
}
10+
11+
super(message)
412

513
this.name = 'BlobsInternalError'
614
}

0 commit comments

Comments
 (0)