Commit 927e757f authored by Robert Knight's avatar Robert Knight

Convert `APIService` to use `fetchJSON`

parent 53eb40d3
import { fetchJSON } from '../util/fetch';
import { replaceURLParams } from '../util/url'; import { replaceURLParams } from '../util/url';
/** /**
...@@ -7,20 +8,6 @@ import { replaceURLParams } from '../util/url'; ...@@ -7,20 +8,6 @@ import { replaceURLParams } from '../util/url';
* @typedef {import('../../types/api').Profile} Profile * @typedef {import('../../types/api').Profile} Profile
*/ */
/**
* Translate the response from a failed API call into an Error-like object.
*
* @param {Response} response
* @param {Object} data - The parsed JSON response
*/
function translateResponseToError(response, data) {
let message = response.status + ' ' + response.statusText;
if (data?.reason) {
message = message + ': ' + data.reason;
}
return new Error(message);
}
/** /**
* Return a shallow clone of `obj` with all client-only properties removed. * Return a shallow clone of `obj` with all client-only properties removed.
* Client-only properties are marked by a '$' prefix. * Client-only properties are marked by a '$' prefix.
...@@ -143,36 +130,15 @@ function createAPICall( ...@@ -143,36 +130,15 @@ function createAPICall(
} }
} }
let response; // nb. Don't "simplify" the lines below to `return fetchJSON(...)` as this
try { // would cause `onRequestFinished` to be called before the API response
response = await fetch(apiURL.toString(), { // is received.
const result = await fetchJSON(apiURL.toString(), {
body: data ? JSON.stringify(stripInternalProperties(data)) : null, body: data ? JSON.stringify(stripInternalProperties(data)) : null,
headers, headers,
method: descriptor.method, method: descriptor.method,
}); });
} catch (err) { return result;
// Re-throw Fetch errors such that they all "look the same" (different
// browsers throw different Errors on Fetch failure). This allows
// Fetch failures to be either handled in particular ways higher up
// or for them to be ignored in error reporting (see `sentry` config).
throw new Error(`Fetch operation failed for URL '${url}'`);
}
const status = response.status;
let responseBody;
if (status >= 200 && status !== 204 && status < 500) {
responseBody = await response.json();
} else {
responseBody = await response.text();
}
if (status >= 400) {
// Translate the API result into an `Error` to follow the convention that
// Promises should be rejected with an Error or Error-like object.
throw translateResponseToError(response, responseBody);
}
return responseBody;
} finally { } finally {
onRequestFinished(); onRequestFinished();
} }
......
...@@ -200,8 +200,7 @@ describe('APIService', () => { ...@@ -200,8 +200,7 @@ describe('APIService', () => {
// Network error // Network error
status: null, status: null,
body: 'Service unreachable.', body: 'Service unreachable.',
expectedMessage: expectedMessage: 'Network request failed: Service unreachable.',
"Fetch operation failed for URL 'https://example.com/api/profile'",
}, },
{ {
// Request failed with an error given in the JSON body // Request failed with an error given in the JSON body
...@@ -210,14 +209,15 @@ describe('APIService', () => { ...@@ -210,14 +209,15 @@ describe('APIService', () => {
body: { body: {
reason: 'Thing not found', reason: 'Thing not found',
}, },
expectedMessage: '404 Not Found: Thing not found', expectedMessage: 'Network request failed (404): Thing not found',
}, },
{ {
// Request failed with a non-JSON response // Request failed with a non-JSON response
status: 500, status: 500,
statusText: 'Server Error', statusText: 'Server Error',
body: 'Internal Server Error', body: 'Internal Server Error',
expectedMessage: '500 Internal Server Error', expectedMessage:
'Network request failed (500): Failed to parse response',
}, },
].forEach(({ status, body, expectedMessage }) => { ].forEach(({ status, body, expectedMessage }) => {
it('rejects the call with an error', () => { it('rejects the call with an error', () => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment