Skip to content

Instantly share code, notes, and snippets.

@dev-dafab
Created April 12, 2021 07:22
Show Gist options
  • Save dev-dafab/6d81e0742448afaa6e6ad530f34bf29f to your computer and use it in GitHub Desktop.
Save dev-dafab/6d81e0742448afaa6e6ad530f34bf29f to your computer and use it in GitHub Desktop.
Intercept HTTP GET fetch Request
const isValueCached = (key: string) => {
  const value = localStorage.getItem(key);
  return value !== null;
};

const xhrResourcesToCache = [
  '/api/resources1',
  '/api/resources2',
  '/api/resources3',
  '/api/resource4'
  // some more resources to cache
];

const isCacheableResource = (method: string, url: string) => {
  const resource = xhrResourcesToCache.find(resource => url.includes(resource));
  if (!resource) {
    return null;
  }
  return method === 'GET' ? resource : null;
};

const canGetFromCache = (method: string, url: string) => {
  const resource = isCacheableResource(method, url);
  if (!resource) {
    return null;
  }
  return isValueCached(`cached-xhr-${resource}`) ? resource : null;
};

const getXhrResourceFromCache = (method: string | undefined, url: string) => {
  if (method === undefined || method !== 'GET') {
    throw Error('not cacheable Method');
  }

  const resource = canGetFromCache(method, url);
  if (canGetFromCache(method, url) !== null) {
    const value = localStorage.getItem(`cached-xhr-${resource}`) || '';
    if (value === '') {
      throw Error('empty cache');
    }
    return JSON.parse(value);
  }
  throw Error('not cacheable resource');
};

const saveInCache = (method: string | undefined, url: string, callback: (resource: string) => void ) => {
  if (method === undefined || method !== 'GET') {
    throw Error('not cacheable Method');
  }
  const resource = isCacheableResource(method, url);
  if (resource === null || localStorage.getItem(`cached-xhr-${resource}`) !== null) {
    throw Error('not cacheable');
  }
  callback(`cached-xhr-${resource}`);
};

const buildResponseFromCache = (value: any): Promise<Response> => {
  return Promise.resolve({
    ok: true,
    status: 200,
    json: async () => value
  } as Response);
};


export const fetchInterceptor = () => {
  const interceptedFetch = window.fetch;
  window.fetch = (input: RequestInfo, init?: RequestInit): Promise<Response> => {
    try {
      const valueFromCache = getXhrResourceFromCache(init?.method, input as string);
      return buildResponseFromCache(valueFromCache);
    } catch (error) {}

    return interceptedFetch(input, { ...init })
      .then(response => {
        try {
          saveInCache(init?.method, response.url, resource => {
            response.json()
              .then(response => {
                localStorage.setItem(resource, JSON.stringify(response));
              });
          });
        } catch (error) {
        }
        return response;
      });
  };
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment