matrix-public-archive/server/lib/fetch-endpoint.js

80 lines
1.9 KiB
JavaScript

'use strict';
const assert = require('assert');
class HTTPResponseError extends Error {
constructor(response, responseText, ...args) {
super(
`HTTP Error Response: ${response.status} ${response.statusText}: ${responseText}\n URL=${response.url}`,
...args
);
this.response = response;
}
}
const checkResponseStatus = async (response) => {
if (response.ok) {
// response.status >= 200 && response.status < 300
return response;
} else {
const responseText = await response.text();
throw new HTTPResponseError(response, responseText);
}
};
async function fetchEndpoint(endpoint, options = {}) {
// We chose `abortSignal` just because it's a less ambiguous name and obvious what
// it's used for.
assert(!options.signal, 'Use `options.abortSignal` instead of `options.signal`');
const { method, accessToken } = options;
const headers = options.headers || {};
if (accessToken) {
headers.Authorization = `Bearer ${accessToken}`;
}
const res = await fetch(endpoint, {
method,
headers,
body: options.body,
// Abort signal to cancel the request
signal: options.abortSignal,
});
await checkResponseStatus(res);
return res;
}
async function fetchEndpointAsText(endpoint, options) {
const res = await fetchEndpoint(endpoint, options);
const data = await res.text();
return { data, res };
}
async function fetchEndpointAsJson(endpoint, options) {
const opts = {
...(options || {}),
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
...(options?.headers || {}),
},
};
if (options?.body) {
opts.body = JSON.stringify(options.body);
}
const res = await fetchEndpoint(endpoint, opts);
const data = await res.json();
return { data, res };
}
module.exports = {
HTTPResponseError,
fetchEndpoint,
fetchEndpointAsText,
fetchEndpointAsJson,
};