Opinionated, caching, retrying fetch client for Node.js with enterprise-grade HTTP features
74
Create pre-configured fetch functions with default options for consistent behavior across an application.
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
});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: 60000msWhen 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 }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}`
}
});
};
};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-happenevals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9