JAVASCRIPT

Simple Client-Side API Caching with `localStorage`

Optimize web application performance by implementing a basic client-side API cache using `localStorage` to store and retrieve frequently accessed data.

const API_CACHE_PREFIX = 'api_cache_';
const CACHE_LIFETIME_MS = 5 * 60 * 1000; // 5 minutes

/**
 * Fetches data from an API, first checking if a valid cached response exists in localStorage.
 * Caches new responses with a timestamp.
 * @param {string} url - The API endpoint URL.
 * @param {object} options - Fetch API options.
 * @returns {Promise<any>} - A promise that resolves with the API response data.
 */
async function fetchWithCache(url, options = {}) {
  const cacheKey = `${API_CACHE_PREFIX}${url}`;
  const now = new Date().getTime();

  // Try to retrieve from cache
  try {
    const cachedItem = localStorage.getItem(cacheKey);
    if (cachedItem) {
      const { data, timestamp } = JSON.parse(cachedItem);
      if (now - timestamp < CACHE_LIFETIME_MS) {
        console.log(`[Cache Hit] for ${url}`);
        return data;
      } else {
        console.log(`[Cache Expired] for ${url}`);
        localStorage.removeItem(cacheKey); // Remove expired item
      }
    }
  } catch (e) {
    console.warn(`Error parsing cache for ${url}:`, e);
    localStorage.removeItem(cacheKey); // Clear potentially corrupt cache
  }

  console.log(`[Fetching Live] for ${url}`);
  try {
    const response = await fetch(url, options);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const liveData = await response.json();

    // Cache the new data
    try {
      const itemToCache = JSON.stringify({ data: liveData, timestamp: now });
      localStorage.setItem(cacheKey, itemToCache);
    } catch (e) {
      console.warn(`Error caching data for ${url}:`, e);
      // If storage limit is exceeded or other caching error, proceed without caching
    }

    return liveData;
  } catch (error) {
    console.error(`Error fetching data for ${url}:`, error);
    throw error;
  }
}

// Example Usage:
/*
(async () => {
  const postUrl = 'https://jsonplaceholder.typicode.com/posts/1';

  console.log('First call (should fetch and cache):');
  await fetchWithCache(postUrl).then(data => console.log('Data:', data.title));

  console.log('
Second call (should use cache):');
  await fetchWithCache(postUrl).then(data => console.log('Data:', data.title));

  // To test expiration, wait 5 minutes or manually set a past timestamp in localStorage
  // or change CACHE_LIFETIME_MS to a very small number like 1000 (1 second) for testing
})();
*/
How it works: This JavaScript snippet provides a `fetchWithCache` function that first attempts to retrieve data from `localStorage`. If a valid, unexpired entry exists, it returns the cached data, preventing an unnecessary API call. Otherwise, it performs a live `fetch` request, stores the new data along with a timestamp in `localStorage`, and then returns it. This simple caching mechanism helps reduce network requests, improve load times, and lessen the burden on the API server for frequently accessed, non-real-time data.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs