Skip to content

Instantly share code, notes, and snippets.

@kibolho
Last active July 1, 2021 11:46
Show Gist options
  • Select an option

  • Save kibolho/17d6c0013d299532654ff128e2c2de18 to your computer and use it in GitHub Desktop.

Select an option

Save kibolho/17d6c0013d299532654ff128e2c2de18 to your computer and use it in GitHub Desktop.
Cache Handler
// TO USE:
// Add a interceptor to the request:
// api.interceptors.request.use((request) => cacheHandler.requestHandler(request));
// api.interceptors.response.use(
// (response) => cacheHandler.responseHandler(response),
// (error) => cacheHandler.errorHandler(error),
// );
import { AxiosRequestConfig, AxiosResponse } from 'axios';
import Storage from './Storage';
import checkResponseErrors from './errors/checkForResponseErrors';
import normalizeApiResponse from './normalizeApiResponse';
interface GetValidCacheResponse {
isValid: boolean;
value?: string;
cacheDate?: Date;
}
export interface ResquestCache {
isIgnoreCache?: boolean;
}
const SEPARATOR = '//**//';
const CACHE_INTERVAL = 60 * 60 * 1000;
const storage = new Storage('cacheStorage');
async function storeInCache(
key: string,
value: string,
timestamp: string,
): Promise<void> {
const finalValue = `${value}${SEPARATOR}${timestamp}`;
await storage.set(key, finalValue);
};
async function getValidCache(key: string): Promise<GetValidCacheResponse> {
const value = await storage.get(key);
if (value === null) {
return {
isValid: false,
};
}
const values = value.split(SEPARATOR);
const timestamp = Number(values[1]);
if (Number.isNaN(timestamp)) {
return {
isValid: false,
};
}
const date = new Date(timestamp);
if (date.toString() === 'Invalid Date') {
return {
isValid: false,
};
}
if (Date.now() - date.getTime() < CACHE_INTERVAL) {
return {
isValid: true,
value: values[0],
cacheDate: date,
};
}
await storage.del(key);
return {
isValid: false,
};
}
async function responseHandler(
response: AxiosResponse<any>,
): Promise<AxiosResponse<any>> {
const responseChecked = await checkResponseErrors(response);
const responseNormalized = await normalizeApiResponse(responseChecked);
if (response.config.method === 'GET' || 'get') {
const key = getKey({ response: response });
if (key) {
const timestamp = Date.now().toString();
const value = JSON.stringify(responseNormalized.data);
await storeInCache(key, value, timestamp);
const cacheDate = new Date(Number(timestamp));
responseNormalized.cacheDate = cacheDate;
}
}
return { ...response, ...responseNormalized };
}
function getKey({
response,
request,
}: {
response?: AxiosResponse<any>;
request?: AxiosRequestConfig;
}): string | undefined {
let key = request?.baseURL ? request?.baseURL + request?.url : request?.url;
let data = request?.data;
if (response) {
key = response.config.baseURL
? response.config.baseURL + response.config.url
: response.config.url;
data = response?.config.data;
}
if (data) {
key += JSON.stringify(data);
}
return key;
}
async function errorHandler(error: any): Promise<any> {
return new Promise((resolve, reject) => {
if (error?.headers?.cached === true) {
resolve(error);
}
reject(error);
});
}
async function requestHandler(
request: AxiosRequestConfig,
): Promise<AxiosRequestConfig> {
if (request.method === 'GET' || 'get') {
const checkIsValidResponse = await getValidCache(getKey({ request }) || '');
if (checkIsValidResponse.isValid && !request?.headers?.isIgnoreCache) {
request.headers.cached = true;
request.cacheDate = checkIsValidResponse.cacheDate;
request.data = JSON.parse(checkIsValidResponse.value || '{}');
return Promise.reject(request);
}
}
return Promise.resolve(request);
}
const cache = {
responseHandler,
errorHandler,
requestHandler,
};
export default cache;
import AsyncStorage from '@react-native-community/async-storage';
export default class Storage {
private name: string;
constructor(name: string) {
this.name = name;
}
async set(
key: string,
value: string | Date | Record<string, unknown>,
): Promise<any> {
return await AsyncStorage.setItem(
`${this.name}-${key}`,
JSON.stringify(value),
);
}
async get(key: string): Promise<any> {
const value = await AsyncStorage.getItem(`${this.name}-${key}`);
if (value) {
return JSON.parse(value);
}
return null;
}
async del(key: string): Promise<any> {
return await AsyncStorage.removeItem(`${this.name}-${key}`);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment