create-fetch-hooks
Version:
A simple and powerful custom React hook (useApi) that simplifies API requests with automatic loading and error states. Ideal for clean and maintainable data fetching in React components.
66 lines (65 loc) • 4.28 kB
JavaScript
import { refreshToken } from "./refreshToken";
import { FetchError } from "./types/FetchError";
import { dataToFormData } from "./utils/dataToFormData";
import { removeMultipleSlashes } from "./utils/removeMultipleSlashes";
import { mergeHeaders } from "./utils/mergeHeader";
export async function post(baseApiUrl, url, dataToPost, options) {
var _a, _b, _c, _d, _e, _f, _g;
const cleanedUrl = removeMultipleSlashes(`${baseApiUrl}/${url}`);
const maxRetries = (_a = options === null || options === void 0 ? void 0 : options.retryCount) !== null && _a !== void 0 ? _a : ((options === null || options === void 0 ? void 0 : options.callRefreshToken) ? 1 : 0);
const retryDelay = (_b = options === null || options === void 0 ? void 0 : options.retryDelay) !== null && _b !== void 0 ? _b : 0;
let responseCode;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
let payload = dataToPost;
if (options === null || options === void 0 ? void 0 : options.convertToFormData) {
payload = dataToFormData(dataToPost, (_c = options === null || options === void 0 ? void 0 : options.removeIfValueIsNullOrUndefined) !== null && _c !== void 0 ? _c : false);
}
else if (options === null || options === void 0 ? void 0 : options.removeIfValueIsNullOrUndefined) {
payload = Object.fromEntries(Object.entries(dataToPost).filter(([, value]) => value !== null && value !== undefined));
}
const response = await fetch(cleanedUrl, {
method: "POST",
headers: mergeHeaders(options === null || options === void 0 ? void 0 : options.headers, {
Authorization: `Bearer ${localStorage.getItem((options === null || options === void 0 ? void 0 : options.accessTokenLocalStorageKey) || "")}`,
...(payload instanceof FormData
? {}
: { "Content-Type": "application/json" }),
}),
signal: options === null || options === void 0 ? void 0 : options.signal,
body: payload instanceof FormData ? payload : JSON.stringify(payload),
});
responseCode = response.status;
if (!response.ok) {
const error = new FetchError(`HTTP error! Status: ${response.status}`, response, response.status);
const refreshTokenConfig = (_d = options === null || options === void 0 ? void 0 : options.callRefreshToken) === null || _d === void 0 ? void 0 : _d.call(options);
if ((refreshTokenConfig === null || refreshTokenConfig === void 0 ? void 0 : refreshTokenConfig.on.includes(response.status)) &&
attempt < maxRetries) {
await new Promise((resolve) => setTimeout(resolve, retryDelay));
await refreshToken(baseApiUrl, refreshTokenConfig.endpoint, refreshTokenConfig.body, refreshTokenConfig.saveAccessTokenFromResponse);
continue; // Retry the request
}
throw error;
}
const res = await response.json();
(_e = options === null || options === void 0 ? void 0 : options.onSuccess) === null || _e === void 0 ? void 0 : _e.call(options, res);
return res;
}
catch (err) {
if (err instanceof Error && err.name !== "AbortError") {
const fetchErr = err instanceof FetchError ? err : new FetchError(err.message);
if (attempt === maxRetries) {
(_f = options === null || options === void 0 ? void 0 : options.onError) === null || _f === void 0 ? void 0 : _f.call(options, fetchErr);
if (fetchErr.status !== undefined) {
responseCode = fetchErr.status || undefined;
}
}
}
}
finally {
if (attempt === maxRetries) {
(_g = options === null || options === void 0 ? void 0 : options.onResponseGot) === null || _g === void 0 ? void 0 : _g.call(options, cleanedUrl, removeMultipleSlashes(cleanedUrl.replace(baseApiUrl, "/")).split("?")[0], responseCode);
}
}
}
}