JAVASCRIPT

Implement a Simple In-Memory Cache for API Responses

Speed up your web applications by implementing a basic in-memory cache with Time-To-Live (TTL) for API responses, reducing redundant network requests.

class ApiCache {
  constructor(ttlMs = 5 * 60 * 1000) { // Default TTL: 5 minutes
    this.cache = new Map();
    this.ttlMs = ttlMs;
  }

  /**
   * Gets data from cache or fetches it if not present/expired.
   * @param {string} key - The cache key.
   * @param {Function} fetcher - Async function to fetch data if not in cache.
   * @returns {Promise<any>} The cached or fetched data.
   */
  async get(key, fetcher) {
    const cachedItem = this.cache.get(key);
    const now = Date.now();

    if (cachedItem && now < cachedItem.expiry) {
      console.log(`Cache hit for key: ${key}`);
      return cachedItem.data;
    }

    console.log(`Cache miss/expired for key: ${key}. Fetching...`);
    try {
      const data = await fetcher();
      this.set(key, data);
      return data;
    } catch (error) {
      console.error(`Failed to fetch data for key ${key}:`, error);
      throw error;
    }
  }

  /**
   * Sets data in the cache.
   * @param {string} key - The cache key.
   * @param {any} data - The data to cache.
   */
  set(key, data) {
    const expiry = Date.now() + this.ttlMs;
    this.cache.set(key, { data, expiry });
    console.log(`Cached data for key: ${key}, expires at ${new Date(expiry).toLocaleTimeString()}`);
  }

  /**
   * Clears a specific item from the cache.
   * @param {string} key - The cache key to clear.
   */
  clear(key) {
    this.cache.delete(key);
    console.log(`Cleared cache for key: ${key}`);
  }

  /**
   * Clears all items from the cache.
   */
  clearAll() {
    this.cache.clear();
    console.log('Cleared all cache items.');
  }
}

// Example Usage:
// const apiCache = new ApiCache(60 * 1000); // 1 minute TTL

// async function fetchProducts() {
//   return await apiCache.get('all-products', async () => {
//     const response = await fetch('https://api.example.com/products');
//     if (!response.ok) throw new Error('Failed to fetch products');
//     return response.json();
//   });
// }

// (async () => {
//   console.log('First call:');
//   const products1 = await fetchProducts();
//   console.log(products1.slice(0, 2)); // Show first two products

//   await new Promise(resolve => setTimeout(resolve, 500)); // Wait a bit

//   console.log('
Second call (should be from cache):');
//   const products2 = await fetchProducts();
//   console.log(products2.slice(0, 2));

//   await new Promise(resolve => setTimeout(resolve, 60 * 1000 + 500)); // Wait for cache to expire

//   console.log('
Third call (should re-fetch after TTL):');
//   const products3 = await fetchProducts();
//   console.log(products3.slice(0, 2));
// })();
How it works: This snippet provides a `ApiCache` class for implementing a simple in-memory cache with a Time-To-Live (TTL) mechanism. When `get(key, fetcher)` is called, it first checks if the data exists in the cache and is still valid (not expired). If so, it returns the cached data immediately. Otherwise, it executes the provided `fetcher` function (typically an API call), stores the result with an expiry timestamp, and then returns the data. This significantly reduces redundant API calls for data that doesn't change frequently, improving application performance and reducing server load.

Need help integrating this into your project?

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

Hire DigitalCodeLabs