in superset-frontend/packages/superset-ui-core/src/connection/callApi/callApi.ts [62:181]
export default async function callApi({
body,
cache = 'default',
credentials = 'same-origin',
fetchRetryOptions,
headers,
method = 'GET',
mode = 'same-origin',
postPayload,
jsonPayload,
redirect = 'follow',
signal,
stringify = true,
url: url_,
searchParams,
}: CallApi): Promise<Response> {
const fetchWithRetry = fetchRetry(fetch, fetchRetryOptions);
const url = `${getFullUrl(url_, searchParams)}`;
const request = {
body,
cache,
credentials,
headers,
method,
mode,
redirect,
signal,
};
if (
method === 'GET' &&
cache !== 'no-store' &&
cache !== 'reload' &&
CACHE_AVAILABLE &&
window.location?.protocol === 'https:'
) {
let supersetCache: Cache | null = null;
try {
supersetCache = await caches.open(CACHE_KEY);
const cachedResponse = await supersetCache.match(url);
if (cachedResponse) {
// if we have a cached response, send its ETag in the
// `If-None-Match` header in a conditional request
const etag = cachedResponse.headers.get('Etag') as string;
request.headers = { ...request.headers, 'If-None-Match': etag };
}
} catch {
// If superset is in an iframe and third-party cookies are disabled, caches.open throws
}
const response = await fetchWithRetry(url, request);
if (supersetCache && response.status === HTTP_STATUS_NOT_MODIFIED) {
const cachedFullResponse = await supersetCache.match(url);
if (cachedFullResponse) {
return cachedFullResponse.clone();
}
throw new Error('Received 304 but no content is cached!');
}
if (
supersetCache &&
response.status === HTTP_STATUS_OK &&
response.headers.get('Etag')
) {
supersetCache.delete(url);
supersetCache.put(url, response.clone());
}
return response;
}
if (method === 'POST' || method === 'PATCH' || method === 'PUT') {
if (postPayload && jsonPayload) {
throw new Error('Please provide only one of jsonPayload or postPayload');
}
if (postPayload instanceof FormData) {
request.body = postPayload;
} else if (postPayload) {
const payload = tryParsePayload(postPayload);
if (payload && typeof payload === 'object') {
// using FormData has the effect that Content-Type header is set to `multipart/form-data`,
// not e.g., 'application/x-www-form-urlencoded'
const formData: FormData = new FormData();
Object.keys(payload).forEach(key => {
const value = (payload as JsonObject)[key] as JsonValue;
if (typeof value !== 'undefined') {
let valueString;
try {
// We have seen instances where casting to String() throws error
// This check allows all valid attributes to be appended to the formData
// while logging error to console for any attribute that fails the cast to String
valueString = stringify ? JSON.stringify(value) : String(value);
} catch (e) {
// eslint-disable-next-line no-console
console.error(
`Unable to convert attribute '${key}' to a String(). '${key}' was not added to the formData in request.body for call to ${url}`,
value,
e,
);
}
if (valueString !== undefined) {
formData.append(key, valueString);
}
}
});
request.body = formData;
}
}
if (jsonPayload !== undefined) {
request.body = JSON.stringify(jsonPayload);
request.headers = {
...request.headers,
'Content-Type': 'application/json',
};
}
}
return fetchWithRetry(url, request);
}