diff --git a/src/main.test.ts b/src/main.test.ts index 92032ee..b6e7449 100644 --- a/src/main.test.ts +++ b/src/main.test.ts @@ -93,6 +93,35 @@ describe('get', () => { expect(await blobs.get(key)).toBeNull() }) + test('Throws when the API returns a non-200 status code', async () => { + const fetcher = async (...args: Parameters) => { + const [url, options] = args + const headers = options?.headers as Record + + expect(options?.method).toBe('get') + + if (url === `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`) { + expect(headers.authorization).toBe(`Bearer ${apiToken}`) + + return new Response(null, { status: 401, statusText: 'Unauthorized' }) + } + + throw new Error(`Unexpected fetch call: ${url}`) + } + + const blobs = new Blobs({ + authentication: { + token: apiToken, + }, + fetcher, + siteID, + }) + + expect(async () => await blobs.get(key)).rejects.toThrowError( + 'get operation has failed: API returned a 401 response', + ) + }) + test('Throws when a pre-signed URL returns a non-200 status code', async () => { const fetcher = async (...args: Parameters) => { const [url, options] = args @@ -242,6 +271,35 @@ describe('set', () => { await blobs.set(key, value, { ttl }) }) + + test('Throws when the API returns a non-200 status code', async () => { + const fetcher = async (...args: Parameters) => { + const [url, options] = args + const headers = options?.headers as Record + + expect(options?.method).toBe('put') + + if (url === `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`) { + expect(headers.authorization).toBe(`Bearer ${apiToken}`) + + return new Response(null, { status: 401 }) + } + + throw new Error(`Unexpected fetch call: ${url}`) + } + + const blobs = new Blobs({ + authentication: { + token: apiToken, + }, + fetcher, + siteID, + }) + + expect(async () => await blobs.set(key, 'value')).rejects.toThrowError( + 'put operation has failed: API returned a 401 response', + ) + }) }) describe('delete', () => { @@ -281,4 +339,37 @@ describe('delete', () => { await blobs.delete(key) }) + + test('Throws when the API returns a non-200 status code', async () => { + const fetcher = async (...args: Parameters) => { + const [url, options] = args + const headers = options?.headers as Record + + expect(options?.method).toBe('delete') + + if (url === `https://api.netlify.com/api/v1/sites/${siteID}/blobs/${key}?context=production`) { + expect(headers.authorization).toBe(`Bearer ${apiToken}`) + + return new Response(null, { status: 401 }) + } + + if (url === signedURL) { + return new Response('Something went wrong', { status: 401 }) + } + + throw new Error(`Unexpected fetch call: ${url}`) + } + + const blobs = new Blobs({ + authentication: { + token: apiToken, + }, + fetcher, + siteID, + }) + + expect(async () => await blobs.delete(key)).rejects.toThrowError( + 'delete operation has failed: API returned a 401 response', + ) + }) }) diff --git a/src/main.ts b/src/main.ts index 29e6e47..4fc73b2 100644 --- a/src/main.ts +++ b/src/main.ts @@ -78,6 +78,11 @@ export class Blobs { const apiURL = `${this.authentication.apiURL}/api/v1/sites/${this.siteID}/blobs/${key}?context=${this.context}` const headers = { authorization: `Bearer ${this.authentication.token}` } const res = await this.fetcher(apiURL, { headers, method }) + + if (res.status !== 200) { + throw new Error(`${method} operation has failed: API returned a ${res.status} response`) + } + const { url } = await res.json() return {