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';
/**
......@@ -7,20 +8,6 @@ import { replaceURLParams } from '../util/url';
* @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.
* Client-only properties are marked by a '$' prefix.
......@@ -143,36 +130,15 @@ function createAPICall(
}
}
let response;
try {
response = await fetch(apiURL.toString(), {
body: data ? JSON.stringify(stripInternalProperties(data)) : null,
headers,
method: descriptor.method,
});
} catch (err) {
// 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;
// nb. Don't "simplify" the lines below to `return fetchJSON(...)` as this
// would cause `onRequestFinished` to be called before the API response
// is received.
const result = await fetchJSON(apiURL.toString(), {
body: data ? JSON.stringify(stripInternalProperties(data)) : null,
headers,
method: descriptor.method,
});
return result;
} finally {
onRequestFinished();
}
......
......@@ -200,8 +200,7 @@ describe('APIService', () => {
// Network error
status: null,
body: 'Service unreachable.',
expectedMessage:
"Fetch operation failed for URL 'https://example.com/api/profile'",
expectedMessage: 'Network request failed: Service unreachable.',
},
{
// Request failed with an error given in the JSON body
......@@ -210,14 +209,15 @@ describe('APIService', () => {
body: {
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
status: 500,
statusText: 'Server Error',
body: 'Internal Server Error',
expectedMessage: '500 Internal Server Error',
expectedMessage:
'Network request failed (500): Failed to parse response',
},
].forEach(({ status, body, expectedMessage }) => {
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