Low-Level Design : Retry Mechanism on API Failure in React

Low-Level Design : Retry Mechanism on API Failure in React

📌 Problem Statement

In modern web applications, network requests (API calls) can occasionally fail due to reasons such as:

  • Temporary network issues
  • Server overload
  • Timeout errors
  • Unstable mobile connectivity

Without a retry mechanism, these failures result in poor user experience, broken flows, or loss of data submission. Users may need to refresh the page or manually retry, which is inefficient.

There is a need to design a robust, reusable retry mechanism in React that:

  • Automatically retries failed API calls a limited number of times.
  • Provides visual feedback (loading and error states).
  • Prevents overwhelming the server with continuous requests.
  • Allows manual retries if automatic attempts fail.


✅ Solution Overview

We will design a Reusable API Call Hook with Retry Support using:

  • useEffect and useState for managing API state.
  • A retryCount and maxRetries system to limit retries.
  • Exponential backoff (optional) to delay subsequent attempts.
  • A reusable RetryButton for manual retry after automatic attempts fail.


⚙️ Detailed Design

1. Key Components

  • useRetryApi (Custom Hook) Handles API calling, automatic retry logic, and state management.
  • RetryButton (Optional) Provides a manual retry option if the max retries are exhausted.
  • Loading and Error UI Displays loading indicators and appropriate error messages.


2. Flow Diagram

Article content
LLD Flow Diagram

3. Hook: useRetryApi Example

import { useState, useCallback } from 'react';

const useRetryApi = (apiFn, maxRetries = 3, retryDelay = 1000) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [retryCount, setRetryCount] = useState(0);

  const fetchData = useCallback(async () => {
    setLoading(true);
    setError(null);

    try {
      const response = await apiFn();
      setData(response);
    } catch (err) {
      if (retryCount < maxRetries) {
        setRetryCount(retryCount + 1);
        setTimeout(fetchData, retryDelay); // Optional: Exponential backoff can be applied here
      } else {
        setError('Request failed after multiple attempts.');
      }
    } finally {
      setLoading(false);
    }
  }, [apiFn, retryCount, maxRetries, retryDelay]);

  return { data, loading, error, fetchData, retryCount };
};

export default useRetryApi;        

4. Usage Example

const ExampleComponent = () => {
  const { data, loading, error, fetchData, retryCount } = useRetryApi(() => fetch('/api/data').then(res => res.json()), 3);

  return (
    <div>
      {loading && <p>Loading...</p>}
      {error && (
        <div>
          <p>{error}</p>
          <button onClick={fetchData}>Retry Manually</button>
        </div>
      )}
      {data && <div>Data: {JSON.stringify(data)}</div>}
      {!loading && !data && <button onClick={fetchData}>Fetch Data</button>}
    </div>
  );
};        

5. Best Practices

  • Set reasonable retry limits (3-5 max retries).
  • Optional: Add exponential backoff to reduce server stress.
  • Provide manual retry if automatic retries fail.
  • Show clear loading and error messages to the user.
  • Consider using libraries like axios-retry if using Axios for HTTP requests.


✅ Summary

The Retry Mechanism improves reliability and user experience in React applications by:

  • Automatically recovering from temporary failures.
  • Preventing user frustration and manual intervention.
  • Maintaining smooth application flows even in unstable networks.

To view or add a comment, sign in

Others also viewed

Explore topics