JAVASCRIPT

Implementing API Request Retries with Exponential Backoff

Enhance API call reliability with a JavaScript utility for retrying failed requests using an exponential backoff strategy for better fault tolerance.

/**
 * Retries a Promise-based function with exponential backoff.
 * @param {Function} fn The async function to retry.
 * @param {Object} options Configuration for retries.
 * @param {number} [options.maxRetries=5] Maximum number of retry attempts.
 * @param {number} [options.delay=1000] Initial delay in milliseconds before the first retry.
 * @param {number} [options.factor=2] Factor by which the delay increases (e.g., 1000, 2000, 4000...).
 * @param {number} [options.maxDelay=30000] Maximum delay between retries.
 * @param {Function} [options.shouldRetry] Optional function (error) => boolean to determine if an error should trigger a retry.
 * @returns {Promise<any>} The result of the successful function call.
 */
async function retryWithExponentialBackoff(fn, options = {}) {
  const {
    maxRetries = 5,
    delay = 1000, // 1 second
    factor = 2,
    maxDelay = 30000, // 30 seconds
    shouldRetry = (error) => true // By default, retry on any error
  } = options;

  let currentDelay = delay;

  for (let i = 0; i <= maxRetries; i++) {
    try {
      const result = await fn();
      return result;
    } catch (error) {
      if (i < maxRetries && shouldRetry(error)) {
        console.warn(`Attempt ${i + 1}/${maxRetries + 1} failed. Retrying in ${currentDelay / 1000}s... Error: ${error.message}`);
        await new Promise(resolve => setTimeout(resolve, currentDelay));
        currentDelay = Math.min(currentDelay * factor, maxDelay);
      } else {
        console.error(`Failed after ${i + 1} attempts. Last error: ${error.message}`);
        throw error; // Re-throw the error after max retries
      }
    }
  }
}

// --- Example Usage with fetch API ---
async function fetchDataFromApi(url) {
  const response = await fetch(url);
  if (!response.ok) {
    // Example: simulate a temporary server error
    if (response.status >= 500 && response.status < 600) {
        throw new Error(`Server error: ${response.status} ${response.statusText}`);
    }
    throw new Error(`API error: ${response.status} ${response.statusText}`);
  }
  return response.json();
}

const testApiUrl = 'https://jsonplaceholder.typicode.com/posts/1';
const failingApiUrl = 'https://httpstat.us/503'; // Simulates a temporary service unavailable error

async function runExample() {
  console.log('--- Successful API Call (no retries) ---');
  try {
    const data = await retryWithExponentialBackoff(() => fetchDataFromApi(testApiUrl));
    console.log('Data fetched successfully:', data.title);
  } catch (error) {
    console.error('Failed to fetch data:', error.message);
  }

  console.log('
--- Failing API Call (with retries) ---');
  try {
    // Custom retry condition: only retry on 5xx errors
    const data = await retryWithExponentialBackoff(() => fetchDataFromApi(failingApiUrl), {
      maxRetries: 3,
      delay: 500, // Shorter initial delay
      shouldRetry: (error) => error.message.includes('Server error') // Only retry server errors
    });
    console.log('Data fetched successfully after retries:', data); // This won't be reached for 503
  } catch (error) {
    console.error('Failed to fetch data after retries:', error.message);
  }
}

// runExample();
How it works: This JavaScript snippet provides a utility function for robust API integration by implementing retries with exponential backoff. When an API call fails due to transient issues (e.g., network glitches, temporary server overload), this function automatically retries the request after an increasing delay, preventing immediate re-failure and allowing the server time to recover. It includes configurable parameters for maximum retries, initial delay, backoff factor, maximum delay, and even a custom function to determine if an error warrants a retry, significantly improving the reliability of integrations.

Need help integrating this into your project?

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

Hire DigitalCodeLabs