@gkoos/ffetch

4 min read Original article ↗

This package has been deprecated

Author message:

This package has moved to @fetchkit/ffetch. Please update your dependencies.

3.4.0 • Public • Published

npm Downloads GitHub stars

Build codecov

MIT bundlephobia Types

@gkoos/ffetch

A production-ready TypeScript-first drop-in replacement for native fetch, or any fetch-compatible implementation.

ffetch can wrap any fetch-compatible implementation (native fetch, node-fetch, undici, or framework-provided fetch), making it flexible for SSR, edge, and custom environments.

Key Features:

  • Timeouts – per-request or global
  • Retries – exponential backoff + jitter
  • Circuit breaker – automatic failure protection
  • Hooks – logging, auth, metrics, request/response transformation
  • Pending requests – real-time monitoring of active requests
  • Per-request overrides – customize behavior on a per-request basis
  • Universal – Node.js, Browser, Cloudflare Workers, React Native
  • Zero runtime deps – ships as dual ESM/CJS

Quick Start

Install

npm install @gkoos/ffetch

Basic Usage

import createClient from '@gkoos/ffetch'

// Create a client with timeout and retries
const api = createClient({
  timeout: 5000,
  retries: 3,
  retryDelay: ({ attempt }) => 2 ** attempt * 100 + Math.random() * 100,
})

// Make requests
const response = await api('https://api.example.com/users')
const data = await response.json()

Using a Custom fetchHandler (SSR, metaframeworks, or polyfills)

// Example: SvelteKit, Next.js, Nuxt, or node-fetch
import createClient from '@gkoos/ffetch'

// Pass your framework's fetch implementation
const api = createClient({
  fetchHandler: fetch, // SvelteKit/Next.js/Nuxt provide their own fetch
  timeout: 5000,
})

// Or use node-fetch/undici in Node.js
import nodeFetch from 'node-fetch'
const apiNode = createClient({ fetchHandler: nodeFetch })

// All ffetch features work identically
const response = await api('/api/data')

Advanced Example

// Production-ready client with error handling and monitoring
const client = createClient({
  timeout: 10000,
  retries: 2,
  circuit: { threshold: 5, reset: 30000 },
  fetchHandler: fetch, // Use custom fetch if needed
  hooks: {
    before: async (req) => console.log('→', req.url),
    after: async (req, res) => console.log('←', res.status),
    onError: async (req, err) => console.error('Error:', err.message),
    onCircuitOpen: (req) => console.warn('Circuit opened due to:', req.url),
    onCircuitClose: (req) => console.info('Circuit closed after:', req.url),
  },
})

try {
  const response = await client('/api/data')

  // Check HTTP status manually (like native fetch)
  if (!response.ok) {
    console.log('HTTP error:', response.status)
    return
  }

  const data = await response.json()
  console.log('Active requests:', client.pendingRequests.length)
} catch (err) {
  if (err instanceof TimeoutError) {
    console.log('Request timed out')
  } else if (err instanceof RetryLimitError) {
    console.log('Request failed after retries')
  }
}

Documentation

Topic Description
Complete Documentation Start here - Documentation index and overview
API Reference Complete API documentation and configuration options
Advanced Features Per-request overrides, pending requests, circuit breakers, custom errors
Hooks & Transformation Lifecycle hooks, authentication, logging, request/response transformation
Usage Examples Real-world patterns: REST clients, GraphQL, file uploads, microservices
Compatibility Browser/Node.js support, polyfills, framework integration

Environment Requirements

ffetch requires modern AbortSignal APIs:

  • Node.js 20.6+ (for AbortSignal.any)
  • Modern browsers (Chrome 117+, Firefox 117+, Safari 17+, Edge 117+)

If your environment does not support AbortSignal.any (Node.js < 20.6, older browsers), you must install a polyfill before using ffetch. See the compatibility guide for instructions.

Custom fetch support: You can pass any fetch-compatible implementation (native fetch, node-fetch, undici, SvelteKit, Next.js, Nuxt, or a polyfill) via the fetchHandler option. This makes ffetch fully compatible with SSR, edge, metaframework environments, custom backends, and test runners.

"AbortSignal.any is not a function"

Solution: Install a polyfill for AbortSignal.any
npm install abort-controller-x

CDN Usage

<script type="module">
  import createClient from 'https://unpkg.com/@gkoos/ffetch/dist/index.min.js'

  const api = createClient({ timeout: 5000 })
  const data = await api('/api/data').then((r) => r.json())
</script>

Fetch vs. Axios vs. ffetch

Feature Native Fetch Axios ffetch
Timeouts ❌ Manual AbortController ✅ Built-in ✅ Built-in with fallbacks
Retries ❌ Manual implementation ❌ Manual or plugins ✅ Smart exponential backoff
Circuit Breaker ❌ Not available ❌ Manual or plugins ✅ Automatic failure protection
Request Monitoring ❌ Manual tracking ❌ Manual tracking ✅ Built-in pending requests
Error Types ❌ Generic errors ⚠️ HTTP errors only ✅ Specific error classes
TypeScript ⚠️ Basic types ⚠️ Basic types ✅ Full type safety
Hooks/Middleware ❌ Not available ✅ Interceptors ✅ Comprehensive lifecycle hooks
Bundle Size ✅ Native (0kb) ❌ ~13kb minified ✅ ~3kb minified
Modern APIs ✅ Web standards ❌ XMLHttpRequest ✅ Fetch + modern features
Custom Fetch Support ❌ No (global only) ❌ No ✅ Yes (wrap any fetch-compatible implementation, including framework or custom fetch)

Contributing

License

MIT © 2025 gkoos