blob: f11e7d125ec5bc5d4e4004471eee0bd04d084ecf [file] [log] [blame]
import ErrorUtils from "../errors/ErrorUtils";
import UnhandledErrorDispatcher from "../errors/UnhandledErrorDispatcher";
import Cache from "./Cache";
var count = 0;
const parseQueryParams = function (url, queryParams = "") {
if (queryParams && typeof queryParams != "string") {
queryParams = Object.keys(queryParams)
.map(
(key) =>
encodeURIComponent(key) + "=" + encodeURIComponent(queryParams[key])
)
.join("&");
}
if (queryParams && queryParams !== "") {
return url + "?" + queryParams;
} else {
return url;
}
};
const setSpinnerDisplay = function (display) {
let spinner = document.getElementById("airavata-spinner");
spinner.style.display = display;
};
const incrementCount = function () {
count++;
if (count == 1) {
setSpinnerDisplay("block");
}
};
const decrementCount = function () {
if (count > 0) {
count--;
if (count == 0) {
setSpinnerDisplay("none");
}
}
};
const responseCache = new Cache();
export default {
showSpinner: function (promise) {
incrementCount();
promise.then(decrementCount, decrementCount);
// return the promise so that it can be chained
return promise;
},
getCSRFToken: function () {
var csrfToken = document.cookie
.split(";")
.map((val) => val.trim())
.filter((val) => val.startsWith("csrftoken" + "="))
.map((val) => val.split("=")[1]);
if (csrfToken) {
return csrfToken[0];
} else {
return null;
}
},
// For POST, PUT, DELETE
createHeaders: function (
contentType = "application/json",
accept = "application/json"
) {
var csrfToken = this.getCSRFToken();
var headers = new Headers({
"Content-Type": contentType,
Accept: accept,
});
if (csrfToken != null) {
headers.set("X-CSRFToken", csrfToken);
}
return headers;
},
post: function (
url,
body,
queryParams = "",
{
mediaType = "application/json",
ignoreErrors = false,
showSpinner = true,
responseType = "json",
} = {}
) {
var headers = this.createHeaders(mediaType);
// Browsers automatically handle content type for FormData request bodies
if (body instanceof FormData) {
headers.delete("Content-Type");
}
url = parseQueryParams(url, queryParams);
return this.processFetch(url, {
method: "post",
body:
body instanceof FormData || typeof body === "string"
? body
: JSON.stringify(body),
headers: headers,
credentials: "same-origin",
ignoreErrors,
showSpinner,
responseType,
});
},
put: function (
url,
body,
{
mediaType = "application/json",
ignoreErrors = false,
showSpinner = true,
responseType = "json",
} = {}
) {
var headers = this.createHeaders(mediaType);
// Browsers automatically handle content type for FormData request bodies
if (body instanceof FormData) {
headers.delete("Content-Type");
}
return this.processFetch(url, {
method: "put",
body:
body instanceof FormData || typeof body === "string"
? body
: JSON.stringify(body),
headers: headers,
credentials: "same-origin",
ignoreErrors,
showSpinner,
responseType,
});
},
get: function (
url,
queryParams = "",
{
mediaType = "application/json",
ignoreErrors = false,
showSpinner = true,
cache = false,
responseType = "json",
} = {}
) {
if (queryParams && typeof queryParams != "string") {
queryParams = Object.keys(queryParams)
.map(
(key) =>
encodeURIComponent(key) + "=" + encodeURIComponent(queryParams[key])
)
.join("&");
}
if (queryParams) {
url = url + "?" + queryParams;
}
if (cache) {
if (responseCache.has(url)) {
return responseCache.get(url);
}
}
var headers = new Headers({ Accept: mediaType });
const fetchRequest = this.processFetch(url, {
method: "get",
headers: headers,
credentials: "same-origin",
ignoreErrors,
showSpinner,
responseType,
});
if (cache) {
responseCache.put({ key: url, value: fetchRequest });
}
return fetchRequest;
},
delete: function (
url,
{ ignoreErrors = false, showSpinner = true, responseType = "json" } = {}
) {
var headers = this.createHeaders();
return this.processFetch(url, {
method: "delete",
headers: headers,
credentials: "same-origin",
ignoreErrors,
showSpinner,
responseType,
});
},
processFetch: function (
url,
{
method = "get",
headers,
credentials = "same-origin",
body,
ignoreErrors = false,
showSpinner = true,
responseType = "json",
}
) {
const fetchConfig = {
method,
headers,
credentials,
};
if (body) {
fetchConfig.body = body;
}
if (showSpinner) {
incrementCount();
}
return fetch(url, fetchConfig)
.then(
(response) => {
if (showSpinner) {
decrementCount();
}
if (response.ok) {
// No response body
if (response.status === 204) {
return Promise.resolve();
} else {
return Promise.resolve(
response[responseType]().then((responseData) => {
return responseData;
})
);
}
} else {
return response.json().then(
(json) => {
// if json doesn't have detail key, stringify body
let errorMessage = json.detail;
if (!("detail" in json)) {
errorMessage = "Error: " + JSON.stringify(json);
}
const error = new Error(errorMessage);
error.details = this.createErrorDetails({
url,
body,
status: response.status,
responseBody: json,
});
throw error;
},
() => {
// In case JSON parsing fails
const error = new Error(response.statusText);
error.details = this.createErrorDetails({
url,
body,
status: response.status,
});
throw error;
}
);
}
},
(error) => {
error.details = this.createErrorDetails({ url, body });
throw error;
}
)
.catch((error) => {
if (showSpinner) {
decrementCount();
}
// Always report unauthenticated errors so user knows they need to re-authenticate
if (!ignoreErrors || ErrorUtils.isUnauthenticatedError(error)) {
this.reportError(error);
}
throw error;
});
},
createErrorDetails: function ({
url,
body,
status = null,
responseBody = null,
} = {}) {
return {
url,
body,
status,
response: responseBody,
};
},
reportError(error) {
UnhandledErrorDispatcher.reportError({
message: error.message,
error: error,
details: error.details,
});
},
};