@soleil-se/app-util
Version:
Utility functions for WebApps, RESTApps and Widgets in Sitevision.
97 lines (87 loc) • 3.25 kB
JavaScript
import { getRouteUri, stringifyParams } from '../../common';
function getUrl(uri, params) {
if (uri.startsWith('/rest-api') || uri.startsWith('/appresource') || uri.startsWith('/edit-app-config') || !uri.startsWith('/')) {
return uri + stringifyParams(params, { addQueryPrefix: true });
}
return getRouteUri(uri, params);
}
async function toJson(response) {
const text = await response.text();
try {
return JSON.parse(text);
} catch (e) {
return undefined;
}
}
async function responseError(response) {
const json = await toJson(response) || {};
const error = new Error(json?.message || response?.statusText);
Object.entries(json).forEach(([key, value]) => {
error[key] = value;
});
error.status = response.status;
return error;
}
async function handleResponse(response) {
if (!response.ok) {
throw await responseError(response);
}
const json = await toJson(response);
if (!json) {
throw new Error('Response could not be parsed as JSON.');
}
return json;
}
function isWidget() {
return !!window?.sv?.PageContext?.dashboardId;
}
function getWidgetOptions(options) {
return {
...options,
params: {
svAjaxReqParam: 'ajax',
...options.params,
},
headers: {
...options.headers,
'X-Requested-With': 'XMLHttpRequest',
},
};
}
/**
* @typedef {Object} ExtensionOptions
* @property {Object<string,any>} params - The parameters to be included in the request URL.
* @property {number} retries - The number of retries to attempt in case of a timeout error.
*
* @typedef {RequestInit & ExtensionOptions} Options
*/
/**
* Fetches JSON data from a specified URI.
* URI:s starting with `/rest-api`, `/appresource`, `/edit-app-config` or a protocol, for example
* `https://` will be left as is. Other URI:s willbe converted to match a route in the current app
* with `getRouteUri`.
*
* @param {string} uri - The URI to fetch JSON data from.
* @param {Options} options - The options for the fetch request with some extensions.
* @param {string} options.method - The HTTP method to use in the request.
* @param {object} options.params - The parameters to be included in the request URL.
* @param {object} options.body - The body to include in the request.
* @param {number} options.retries - The number of retries to attempt in case of a timeout error.
* @param {object} options.headers - The headers to be included in the request.
* @returns {Promise<Object>} A promise that resolves to the JSON response.
* @throws {Error} If the response is not successful or cannot be parsed as JSON.
*/
export default function fetchJson(uri, options = {}) {
const { params = {}, retries = 0, ...rest } = isWidget() ? getWidgetOptions(options) : options;
return fetch(getUrl(uri, params), rest)
.then(handleResponse)
.catch((error) => {
const isTimeout = error.status === 504 || error.status === 408 || error.message?.includes('SocketTimeoutException');
if (isTimeout && retries > 0) {
return fetchJson(uri, { ...rest, params, retries: retries - 1 });
}
// eslint-disable-next-line no-param-reassign
error.aborted = error.name === 'AbortError';
return Promise.reject(error);
});
}