JAVASCRIPT

Robust API Request Retries with Exponential Backoff

Enhance API integration reliability by implementing an exponential backoff retry mechanism for failed requests, preventing rate limit issues and transient errors.

const axios = require('axios');

async function callApiWithRetries(apiCallFn, maxRetries = 5, initialDelay = 1000) {
  let retries = 0;
  while (retries < maxRetries) {
    try {
      return await apiCallFn();
    } catch (error) {
      // Check for common retryable errors: 429 Too Many Requests, 5xx server errors
      const statusCode = error.response ? error.response.status : null;
      if ([429, 500, 502, 503, 504].includes(statusCode) && retries < maxRetries - 1) {
        const delay = initialDelay * Math.pow(2, retries) + Math.random() * 500; // Exponential backoff with jitter
        console.warn(`API call failed (status: ${statusCode}). Retrying in ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
        retries++;
      } else {
        // Not a retryable error or max retries reached
        console.error('API call failed permanently:', error.response ? error.response.data : error.message);
        throw error;
      }
    }
  }
  throw new Error('Max retries reached, API call failed.');
}

// Example API function to wrap
const fetchUserData = async (userId) => {
  console.log(`Attempting to fetch data for user ${userId}`);
  // Simulate an API call that might fail
  const randomFailure = Math.random();
  if (randomFailure < 0.3) { // 30% chance of a 429 error
    const error = new Error('Simulated 429 Too Many Requests');
    error.response = { status: 429, data: { message: 'Rate limit exceeded' } };
    throw error;
  }
  if (randomFailure > 0.8) { // 20% chance of a 500 error
    const error = new Error('Simulated 500 Internal Server Error');
    error.response = { status: 500, data: { message: 'Server error' } };
    throw error;
  }
  return { userId, name: `User ${userId}`, data: 'Some data from API' };
};

// Usage:
// (async () => {
//   try {
//     const data = await callApiWithRetries(() => fetchUserData(123));
//     console.log('Successfully fetched data:', data);
//   } catch (err) {
//     console.error('Failed after retries:', err.message);
//   }
// })();
How it works: This snippet provides a robust strategy for handling transient API errors and rate limits using exponential backoff with jitter. It wraps an asynchronous API call function, automatically retrying the request with increasing delays if specific HTTP status codes (like 429 for rate limits or 5xx server errors) are encountered. Jitter (random additional delay) is added to prevent all clients from retrying simultaneously, reducing the chance of overwhelming the API again.

Need help integrating this into your project?

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

Hire DigitalCodeLabs