Fetch Smartly

1.0.2 · active · verified Wed Apr 22

Fetch Smartly is a zero-dependency, isomorphic HTTP client that wraps the native `fetch` API to provide production-grade resilience and intelligence for Node.js 18+, browsers, Cloudflare Workers, Deno, and Bun environments. It addresses common pain points of raw `fetch` by incorporating intelligent retry mechanisms with exponential backoff and jitter, respecting `Retry-After` headers, and automatically avoiding retries for 4xx client errors. The library offers a comprehensive typed error hierarchy, including `NetworkError`, `TimeoutError`, `HttpError`, and `RateLimitError`, enabling granular error handling via `instanceof` checks. Key features also include an automatic circuit breaker for failure isolation, request deduplication for identical concurrent GET/HEAD requests, and an offline queue with pluggable storage for replaying failed requests. Currently at version 1.0.2, the package is actively maintained with recent minor updates, distinguishing itself through its lightweight nature, strict TypeScript support, and robust, built-in resilience features.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to use `fetchWithRetry` with intelligent retry logic, a request timeout, and a circuit breaker. It also shows how to handle the library's custom error hierarchy, including `HttpError`, `NetworkError`, `TimeoutError`, and `RateLimitError`, for robust error management.

import { fetchWithRetry, HttpError, NetworkError, TimeoutError, RateLimitError } from 'fetch-smartly';

async function fetchDataWithResilience() {
  try {
    const response = await fetchWithRetry({
      url: 'https://api.github.com/users/octocat', // Example public API endpoint
      method: 'GET',
      retry: {
        attempts: 5,
        delay: 'exponential', // Use exponential backoff
        maxDelay: 5000, // Cap retry delay at 5 seconds
        shouldRetry: (error) => !(error instanceof HttpError && error.status >= 400 && error.status < 500), // Don't retry client errors
      },
      timeout: 3000, // 3-second timeout for the request
      circuitBreaker: {
        threshold: 3, // Open after 3 consecutive failures
        resetTimeout: 10000, // Try to close after 10 seconds
      },
      headers: {
        'Content-Type': 'application/json',
        'User-Agent': 'fetch-smartly-example',
        'Authorization': `Bearer ${process.env.API_KEY ?? ''}` // Example of using an environment variable for auth
      }
    });

    if (response.ok) {
      const data = await response.json();
      console.log('Fetched data:', data);
    } else {
      console.error('HTTP Error:', response.status, response.statusText);
    }
  } catch (error) {
    if (error instanceof HttpError) {
      console.error(`Request failed with HTTP status ${error.status}: ${error.message}`);
      if (error instanceof RateLimitError) {
        console.warn(`Rate limited! Retry-After: ${error.retryAfter} seconds`);
      }
    } else if (error instanceof NetworkError) {
      console.error('Network connection error:', error.message);
    } else if (error instanceof TimeoutError) {
      console.error('Request timed out:', error.message);
    } else {
      console.error('An unexpected error occurred:', error);
    }
  }
}

fetchDataWithResilience();

view raw JSON →