CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-make-fetch-happen

Opinionated, caching, retrying fetch client for Node.js with enterprise-grade HTTP features

74

1.68x
Overview
Eval results
Files

configuration.mddocs/

Configuration and Defaults

Create pre-configured fetch functions with default options for consistent behavior across an application.

Capabilities

Creating Default Fetch Functions

The defaults method creates a new fetch function with pre-configured default options.

/**
 * Creates a new fetch function with default options
 * @param {string} [defaultUrl] - Default URL to use if none provided to the fetch call
 * @param {FetchOptions} [defaultOptions] - Default options to merge with each request
 * @returns {FetchFunction} New fetch function with defaults applied
 */
function fetch.defaults(defaultUrl, defaultOptions);

/**
 * Alternative signature when only options are provided
 * @param {FetchOptions} defaultOptions - Default options to apply
 * @returns {FetchFunction} New fetch function with defaults applied
 */
function fetch.defaults(defaultOptions);

Usage Examples:

const fetch = require('make-fetch-happen');

// Create fetch with default cache settings
const cachedFetch = fetch.defaults({
  cachePath: './my-app-cache',
  cache: 'default',
  retry: { retries: 2 }
});

// Use the configured fetch
const response = await cachedFetch('https://api.example.com/users');

// Create fetch with default URL and options
const apiFetch = fetch.defaults('https://api.example.com', {
  headers: { 'Authorization': 'Bearer token123' },
  timeout: 30000
});

// Fetch from the default URL
const users = await apiFetch('/users'); // Fetches https://api.example.com/users

// Override defaults for specific requests
const posts = await apiFetch('/posts', {
  timeout: 60000, // Override default timeout
  headers: { 'Accept': 'application/json' } // Merge with default headers
});

Chaining Defaults

Default fetch functions also have a defaults method, allowing for layered configuration.

/**
 * Chained defaults method on defaulted fetch functions
 * @param {string} [defaultUrl] - Additional default URL
 * @param {FetchOptions} [defaultOptions] - Additional default options
 * @returns {FetchFunction} New fetch function with layered defaults
 */
defaultedFetch.defaults(defaultUrl, defaultOptions);

Usage Examples:

// Base configuration for all API calls
const baseFetch = fetch.defaults({
  cachePath: './cache',
  retry: { retries: 3 }
});

// Specific configuration for authenticated calls
const authFetch = baseFetch.defaults({
  headers: { 'Authorization': 'Bearer token123' }
});

// Specific configuration for admin API
const adminFetch = authFetch.defaults('https://admin-api.example.com', {
  timeout: 60000,
  headers: { 'X-Admin-Key': 'admin123' }
});

// Each level inherits and extends previous defaults
const response = await adminFetch('/users'); 
// URL: https://admin-api.example.com/users
// Headers: Authorization, X-Admin-Key
// Cache: ./cache
// Retry: 3 attempts
// Timeout: 60000ms

Option Merging Behavior

When creating defaulted fetch functions, options are merged according to these rules:

/**
 * Options merging priority (highest to lowest):
 * 1. Request-specific options (passed to fetch call)
 * 2. Layered default options (from chained .defaults() calls)
 * 3. Base default options (from first .defaults() call)
 * 
 * Special merging rules:
 * - Headers are merged (request headers override defaults)
 * - All other options use simple override behavior
 */

Usage Examples:

const defaultFetch = fetch.defaults({
  headers: {
    'User-Agent': 'MyApp/1.0',
    'Accept': 'application/json'
  },
  timeout: 30000,
  retry: { retries: 2 }
});

// Headers are merged, other options override
const response = await defaultFetch('https://api.example.com/data', {
  headers: {
    'Authorization': 'Bearer token', // Added to defaults
    'Accept': 'application/xml'      // Overrides default
  },
  timeout: 60000 // Overrides default
  // retry still uses default { retries: 2 }
});

// Final request has:
// Headers: User-Agent: MyApp/1.0, Accept: application/xml, Authorization: Bearer token
// Timeout: 60000
// Retry: { retries: 2 }

Configuration Patterns

Common patterns for organizing fetch configurations:

// Environment-based configuration
const createFetch = (env) => {
  const baseConfig = {
    cachePath: `./cache-${env}`,
    retry: env === 'production' ? { retries: 5 } : { retries: 1 }
  };
  
  if (env === 'development') {
    baseConfig.proxy = 'http://localhost:8888';
  }
  
  return fetch.defaults(baseConfig);
};

// Service-specific configuration
const apiConfig = {
  cachePath: './api-cache',
  timeout: 30000,
  retry: { retries: 3, factor: 2 }
};

const imageConfig = {
  cachePath: './image-cache', 
  timeout: 120000,
  size: 50 * 1024 * 1024, // 50MB max
  integrity: true // Enable integrity checking
};

const apiFetch = fetch.defaults(apiConfig);
const imageFetch = fetch.defaults(imageConfig);

// Authentication middleware pattern
const createAuthenticatedFetch = (getToken) => {
  const baseFetch = fetch.defaults({
    cachePath: './auth-cache',
    retry: { retries: 2 }
  });
  
  return async (url, options = {}) => {
    const token = await getToken();
    return baseFetch(url, {
      ...options,
      headers: {
        ...options.headers,
        'Authorization': `Bearer ${token}`
      }
    });
  };
};

TypeScript Support

When using TypeScript, default functions maintain proper type safety:

import fetch, { FetchOptions, Response } from 'make-fetch-happen';

// Type-safe default configuration
const apiConfig: FetchOptions = {
  cachePath: './cache',
  timeout: 30000,
  headers: { 'Content-Type': 'application/json' }
};

const apiFetch = fetch.defaults('https://api.example.com', apiConfig);

// Return type is still Promise<Response>
const response: Promise<Response> = apiFetch('/users');

Install with Tessl CLI

npx tessl i tessl/npm-make-fetch-happen

docs

caching.md

configuration.md

core-fetch.md

index.md

network.md

retry.md

security.md

tile.json