JAVASCRIPT

Robust API Request with Retry Logic

Implement a JavaScript fetch wrapper that automatically retries failed API requests, improving reliability for transient network issues or server errors.

async function fetchWithRetry(url, options = {}, retries = 3, delay = 1000) {
  for (let i = 0; i < retries; i++) {
    try {
      const response = await fetch(url, options);
      if (response.ok) {
        return response;
      } else if (response.status === 429) {
        // Too Many Requests - respect Retry-After header if present
        const retryAfter = response.headers.get('Retry-After');
        const retryDelay = retryAfter ? parseInt(retryAfter, 10) * 1000 : delay * Math.pow(2, i); // Exponential backoff
        console.warn(`Rate limited. Retrying in ${retryDelay / 1000}s...`);
        await new Promise(resolve => setTimeout(resolve, retryDelay));
      } else if (response.status >= 500 && response.status < 600) {
        // Server error, may be transient
        console.warn(`Server error (${response.status}). Retrying in ${delay / 1000}s...`);
        await new Promise(resolve => setTimeout(resolve, delay * Math.pow(2, i))); // Exponential backoff
      } else {
        // Non-retriable client error (4xx) or other unhandled status
        const errorData = await response.json().catch(() => response.text());
        throw new Error(`API error ${response.status}: ${JSON.stringify(errorData)}`);
      }
    } catch (error) {
      if (error instanceof TypeError) {
        // Network error (e.g., DNS failure, no internet) - often retriable
        console.warn(`Network error: ${error.message}. Retrying in ${delay / 1000}s...`);
        await new Promise(resolve => setTimeout(resolve, delay * Math.pow(2, i))); // Exponential backoff
      } else {
        throw error; // Re-throw non-retryable errors
      }
    }
  }
  throw new Error(`Failed to fetch ${url} after ${retries} attempts.`);
}

// Example usage:
// (async () => {
//   try {
//     const data = await fetchWithRetry('https://api.example.com/data', { method: 'GET' });
//     const jsonResponse = await data.json();
//     console.log('Fetched data:', jsonResponse);
//   } catch (error) {
//     console.error('Failed to fetch data after retries:', error.message);
//   }
// })();
How it works: This snippet provides a `fetchWithRetry` function that wraps the standard Fetch API, adding resilience to API integrations. It automatically retries requests multiple times with an exponential backoff strategy for network errors, server-side issues (5xx), and rate limiting (429). It also respects the `Retry-After` header for rate limits and explicitly handles non-retriable client errors (4xx) by throwing immediately, ensuring your application doesn't get stuck in a retry loop for permanent issues.

Need help integrating this into your project?

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

Hire DigitalCodeLabs