Skip to content

Commit d6b4965

Browse files
committed
feat: throw when API returns an error code
1 parent 1c8299c commit d6b4965

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

src/main.test.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,35 @@ describe('get', () => {
9393
expect(await blobs.get(key)).toBeNull()
9494
})
9595

96+
test('Throws when the API returns a non-200 status code', async () => {
97+
const fetcher = async (...args: Parameters<typeof globalThis.fetch>) => {
98+
const [url, options] = args
99+
const headers = options?.headers as Record<string, string>
100+
101+
expect(options?.method).toBe('get')
102+
103+
if (url === `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`) {
104+
expect(headers.authorization).toBe(`Bearer ${apiToken}`)
105+
106+
return new Response(null, { status: 401, statusText: 'Unauthorized' })
107+
}
108+
109+
throw new Error(`Unexpected fetch call: ${url}`)
110+
}
111+
112+
const blobs = new Blobs({
113+
authentication: {
114+
token: apiToken,
115+
},
116+
fetcher,
117+
siteID,
118+
})
119+
120+
expect(async () => await blobs.get(key)).rejects.toThrowError(
121+
'get operation has failed: API returned a 401 response',
122+
)
123+
})
124+
96125
test('Throws when a pre-signed URL returns a non-200 status code', async () => {
97126
const fetcher = async (...args: Parameters<typeof globalThis.fetch>) => {
98127
const [url, options] = args
@@ -242,6 +271,41 @@ describe('set', () => {
242271

243272
await blobs.set(key, value, { ttl })
244273
})
274+
275+
test('Throws when a pre-signed URL returns a non-200 status code', async () => {
276+
const fetcher = async (...args: Parameters<typeof globalThis.fetch>) => {
277+
const [url, options] = args
278+
const headers = options?.headers as Record<string, string>
279+
280+
expect(options?.method).toBe('put')
281+
282+
if (url === `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`) {
283+
const data = JSON.stringify({ url: signedURL })
284+
285+
expect(headers.authorization).toBe(`Bearer ${apiToken}`)
286+
287+
return new Response(data)
288+
}
289+
290+
if (url === signedURL) {
291+
return new Response('Something went wrong', { status: 401 })
292+
}
293+
294+
throw new Error(`Unexpected fetch call: ${url}`)
295+
}
296+
297+
const blobs = new Blobs({
298+
authentication: {
299+
token: apiToken,
300+
},
301+
fetcher,
302+
siteID,
303+
})
304+
305+
expect(async () => await blobs.set(key, 'value')).rejects.toThrowError(
306+
'put operation has failed: Something went wrong',
307+
)
308+
})
245309
})
246310

247311
describe('delete', () => {
@@ -281,4 +345,39 @@ describe('delete', () => {
281345

282346
await blobs.delete(key)
283347
})
348+
349+
test('Throws when a pre-signed URL returns a non-200 status code', async () => {
350+
const fetcher = async (...args: Parameters<typeof globalThis.fetch>) => {
351+
const [url, options] = args
352+
const headers = options?.headers as Record<string, string>
353+
354+
expect(options?.method).toBe('delete')
355+
356+
if (url === `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`) {
357+
const data = JSON.stringify({ url: signedURL })
358+
359+
expect(headers.authorization).toBe(`Bearer ${apiToken}`)
360+
361+
return new Response(data)
362+
}
363+
364+
if (url === signedURL) {
365+
return new Response('Something went wrong', { status: 401 })
366+
}
367+
368+
throw new Error(`Unexpected fetch call: ${url}`)
369+
}
370+
371+
const blobs = new Blobs({
372+
authentication: {
373+
token: apiToken,
374+
},
375+
fetcher,
376+
siteID,
377+
})
378+
379+
expect(async () => await blobs.delete(key)).rejects.toThrowError(
380+
'delete operation has failed: Something went wrong',
381+
)
382+
})
284383
})

src/main.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ export class Blobs {
7878
const apiURL = `${this.authentication.apiURL}/api/v1/sites/${this.siteID}/blobs/${key}?context=${this.context}`
7979
const headers = { authorization: `Bearer ${this.authentication.token}` }
8080
const res = await this.fetcher(apiURL, { headers, method })
81+
82+
if (res.status !== 200) {
83+
throw new Error(`${method} operation has failed: API returned a ${res.status} response`)
84+
}
85+
8186
const { url } = await res.json()
8287

8388
return {

0 commit comments

Comments
 (0)