custom-api-handler
Version:
The package uses axios library to request APIs and uses local-storage for tokens (auth & refresh).
352 lines (334 loc) • 11.4 kB
text/typescript
import axios, { Method } from "axios";
import {
authToken,
commonErrorMsg,
refreshToken,
refreshTokenNotFound,
responseSuccess,
sessionExpired,
unknownError,
} from "./customMsgs";
import {
isAccessTokenExpired,
isRefreshTokenExpired,
} from "./customValidations";
/**
* API-Handler class for custom API requesting methods with axios
*/
class APIHandler {
private tokenBearerLabel: string = "";
private refreshTokenLabelName: string =
Buffer.from(refreshToken).toString("base64");
private accessTokenLabelName: string =
Buffer.from(authToken).toString("base64");
constructor() {}
/**
* Method to set token label
* @param tokenBearerLabel | Provide Bearer name to be included for tokens added in header for API request (if any)
*/
public setTokenBearerLabel = (tokenBearerLabel: string) => {
this.tokenBearerLabel = tokenBearerLabel;
};
/**
* Method to set refresh-token label name
* @param refreshTokenLabelName | Provide refresh-token label name that is sent from backend-server.
*/
public setRefreshTokenLabelName = (refreshTokenLabelName: string) => {
this.refreshTokenLabelName = Buffer.from(refreshTokenLabelName).toString(
"base64"
);
localStorage.setItem(this.refreshTokenLabelName, "");
};
/**
* Method to get current used refresh-token label name
* @returns | Refresh-Token Label Name
*/
public getRefreshTokenLabelName = () =>
Buffer.from(this.refreshTokenLabelName, "base64").toString();
/**
* Method to set access-token label name
* @param accessTokenLabelName | Provide access-token label name that is sent from backend-server.
*/
public setAccessTokenLabelName = (accessTokenLabelName: string) => {
this.accessTokenLabelName =
Buffer.from(accessTokenLabelName).toString("base64");
localStorage.setItem(this.accessTokenLabelName, "");
};
/**
* Method to get current used access-token label name
* @returns | Access-Token Label Name
*/
public getAccessTokenLabelName = () =>
Buffer.from(this.accessTokenLabelName, "base64").toString();
/**
* Method to validate params
* @param obj | Provide params in object for validation
* @returns | custom msg (if error) or false
*/
private validateParams = (obj: any) => {
for (let objProp in obj) {
if (
(obj[objProp] === null || obj[objProp] === undefined) &&
objProp !== "params" &&
objProp !== "data"
) {
return `${commonErrorMsg} ${objProp}!`;
}
}
return false;
};
/**
* Method for requesting API with options for including auth & refresh tokens in API request header
* @param {String} url | Provide API URL to be requested
* @param {Method} method | Provide request type
* @param {any} data | Provide request-body(if any)
* @param {any} params | Provide request-params(if any)
* @param {String} baseURL | Provide API Base-URL for the request
* @param {Boolean} isAuthTokenRequiredInHeader | Provide true/false for adding auth-token from local-storage in header
* @param {Boolean} isRefTokenRequiredInHeader | Provide true/false for adding refresh-token from local-storage in header
* @returns | Requested API response promise
*/
public requestApi = async (
url: string = "",
method: Method = "get",
data: any = null,
params: any = null,
baseURL: string = "",
isAuthTokenRequiredInHeader: boolean = true,
isRefTokenRequiredInHeader: boolean = true
) => {
try {
let paramsValidation = this.validateParams({
url,
method,
data,
params,
baseURL,
isAuthTokenRequiredInHeader,
isRefTokenRequiredInHeader,
});
if (paramsValidation) {
throw new Error(paramsValidation);
} else {
let authTokenValue = "";
let refreshTokenValue = "";
let header = {};
if (isAuthTokenRequiredInHeader && isRefTokenRequiredInHeader) {
authTokenValue = `${this.tokenBearerLabel} ${localStorage.getItem(
this.accessTokenLabelName
)}`;
refreshTokenValue = `${this.tokenBearerLabel} ${localStorage.getItem(
this.refreshTokenLabelName
)}`;
header = {
[this.getAccessTokenLabelName()]: authTokenValue,
[this.getRefreshTokenLabelName()]: refreshTokenValue,
};
} else if (isAuthTokenRequiredInHeader) {
authTokenValue = `${this.tokenBearerLabel} ${localStorage.getItem(
this.accessTokenLabelName
)}`;
header = {
[this.getAccessTokenLabelName()]: authTokenValue,
};
} else if (isRefTokenRequiredInHeader) {
refreshTokenValue = `${this.tokenBearerLabel} ${localStorage.getItem(
this.refreshTokenLabelName
)}`;
header = {
[this.getRefreshTokenLabelName()]: refreshTokenValue,
};
}
return await axios({
baseURL,
url,
method,
data,
headers: header,
params,
})
.then((response) => response)
.catch((error) => {
throw error;
});
}
} catch (error) {
throw error;
}
};
/**
* Method for requesting API with refresh-token wrapper for requesting new auth & refresh tokens before each API request
* @param {String} url | Provide API URL to be requested
* @param {String} rftURL | Provide refresh-token API URL
* @param {Method} method | Provide request type
* @param {any} data | Provide request-body(if any)
* @param {any} params | Provide request-params(if any)
* @param {String} baseURL | Provide API Base-URL for the request
* @param {String} rftBaseURL | Provide refresh-token API Base-URL for the request
* @returns | Requested API response promise
*/
public rftWrapper = async (
url: string = "",
rftURL: string = "",
method: Method = "get",
data: any = null,
params: any = null,
baseURL: string = "",
rftBaseURL: string = ""
) => {
try {
let paramsValidation = this.validateParams({
url,
rftURL,
method,
data,
params,
baseURL,
rftBaseURL,
});
if (paramsValidation) {
throw new Error(paramsValidation);
} else {
let refreshTokenHeaders = {
[this.getAccessTokenLabelName()]: `${
this.tokenBearerLabel
} ${localStorage.getItem(this.accessTokenLabelName)}`,
[this.getRefreshTokenLabelName()]: `${
this.tokenBearerLabel
} ${localStorage.getItem(this.refreshTokenLabelName)}`,
};
return await axios({
baseURL: rftBaseURL,
url: rftURL,
data: "",
headers: refreshTokenHeaders,
method: "GET",
})
.then(async (response) => {
if (
response.data?.response_type?.toUpperCase() === responseSuccess
) {
let responseData = response.data?.response_data;
let authTokenValue = responseData[this.getAccessTokenLabelName()];
let refreshTokenValue =
responseData[this.getRefreshTokenLabelName()];
if (authTokenValue) {
localStorage.setItem(this.accessTokenLabelName, authTokenValue);
}
if (refreshTokenValue) {
localStorage.setItem(
this.refreshTokenLabelName,
refreshTokenValue
);
}
return await this.requestApi(url, method, data, params, baseURL);
} else {
if (response.data?.error_description === refreshTokenNotFound) {
return await this.requestApi(
url,
method,
data,
params,
baseURL
);
}
}
})
.catch((error) => {
setTimeout(() => {
this.removeLocalStorage();
window.location.reload();
}, 2000);
return Promise.reject(new Error(unknownError));
});
}
} catch (error) {
throw error;
}
};
/**
* Method for requesting API with auth & refresh tokens expiry check and requesting new tokens before each API request (if expired)
* @param {String} url | Provide API URL to be requested
* @param {String} rftURL | Provide refresh-token API URL
* @param {Method} method | Provide request type
* @param {any} data | Provide request-body(if any)
* @param {any} params | Provide request-params(if any)
* @param {Boolean} isRFTandATValidationRequired | Provide true/false for including auth-token & refresh-token expiry check
* @param {String} baseURL | Provide API Base-URL for the request
* @param {String} rftBaseURL | Provide refresh-token API Base-URL for the request
* @returns | Requested API response promise
*/
public reqAPIwithRFTWrapper = async (
url: string = "",
rftURL: string = "",
method: Method = "get",
data: any = null,
params: any = null,
isRFTandATValidationRequired: boolean = true,
baseURL: string = "",
rftBaseURL: string = ""
) => {
try {
let paramsValidation = this.validateParams({
url,
rftURL,
method,
data,
params,
isRFTandATValidationRequired,
baseURL,
rftBaseURL,
});
if (paramsValidation) {
throw new Error(paramsValidation);
} else {
if (isRFTandATValidationRequired) {
if (isAccessTokenExpired() && !isRefreshTokenExpired()) {
return await this.rftWrapper(
url,
rftURL,
method,
data,
params,
baseURL,
rftBaseURL
);
} else if (isRefreshTokenExpired()) {
setTimeout(() => {
this.removeLocalStorage();
window.location.reload();
}, 2000);
return Promise.reject(new Error(sessionExpired));
} else {
return await this.requestApi(url, method, data, params, baseURL);
}
} else {
return await this.rftWrapper(
url,
rftURL,
method,
data,
params,
baseURL,
rftBaseURL
);
}
}
} catch (error) {
throw error;
}
};
/**
* Method to remove auth-token & refresh-token from local-storage
*/
private removeLocalStorage = () => {
const localStorageArray = [
this.accessTokenLabelName,
this.refreshTokenLabelName,
];
for (let localStorageItem of localStorageArray) {
localStorage.removeItem(localStorageItem);
}
};
}
export const apiHandler = new APIHandler();