96 lines
2.9 KiB
JavaScript
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;
|
|
}
|
|
}
|
|
|
|
|
|
|