Files
HangmanLab.Frontend/src/utils/requestUtils.js

96 lines
2.9 KiB
JavaScript

import {data} from "react-router-dom";
const ongoingRequests = new Map();
function _default_hash_function(url, method, body){
const url_obj = new URL(url, window.location.origin);
const query_params = [...url_obj.searchParams.entries()]
.sort(([a], [b]) => a.localeCompare(b))
.map(([key, value]) => `${key}=${value}`)
.join("&");
const normalized_url = `${url_obj.origin}${url_obj.pathname}${query_params ? "?" + query_params : ""}`;
const normalized_body = body
? JSON.stringify(
Object.keys(body)
.sort()
.reduce((acc, key) => {
acc[key] = body[key];
return acc;
}, {})
)
: "";
return `${method.toUpperCase()}:${normalized_url}:${normalized_body}`;
}
export async function fetch_(url, init = {}, init_options = {}){
const default_options = {
use_cache: true,
cache_key: _default_hash_function(url, init.method || "GET", init.body || null),
cache_expires: 60,
use_token: true,
};
const options = { ...default_options, ...init_options };
const token = options.use_token ? localStorage.getItem("accessToken") : null;
const request_options = {
...init,
headers: {
...(init.headers || {}),
...(token ? {Authorization: `Bearer ${token}`} : {}),
...(init.method && ['PUT', 'POST'].includes(init.method.toUpperCase())
? {'Content-Type': 'application/json'}
: {}),
}
};
if(options.use_cache && ongoingRequests.has(options.cache_key)){
return ongoingRequests.get(options.cache_key);
}
const now = Date.now();
const cached_data = localStorage.getItem(options.cache_key);
if(options.use_cache && cached_data){
const {data, timestamp} = JSON.parse(cached_data);
if(now - timestamp < options.cache_expires * 1000)
return data;
}
try {
const fetchPromise = fetch(url, request_options)
.then((response) => {
if(!response.ok) {
throw new Error(`RESPONSE_ERROR: ${response.status}`);
}
return response.json();
})
.then((data) => {
if (options.use_cache)
{
localStorage.setItem(
options.cache_key,
JSON.stringify({ data, timestamp: now })
);
ongoingRequests.delete(options.cache_key);
}
return data;
});
if(options.use_cache){
ongoingRequests.set(options.cache_key, fetchPromise);
}
return await fetchPromise;
}catch(error){
if(options.use_cache){
ongoingRequests.delete(options.cache_key);
}
throw error;
}
}