The Easiest & Most Powerful
API Client for JS & TS.
Tired of reinventing token refresh loops, cache TTLs, and retry backoffs for fetch and axios? api-flow-client gives you seamless 401 mutex queuing, smart LRU caching, auto-retry with jitter, and ready-to-use React hooks in one cohesive, featherweight package.
npm install api-flow-client
import { createApi } from 'api-flow-client'
// 1. Single powerful client instance
export const api = createApi({
baseURL: 'https://api.example.com/v1',
// Mutex auth refresh — queues concurrent 401s automatically
auth: {
getAccessToken: () => localStorage.getItem('token'),
refresh: async (refreshToken) => {
const res = await fetch('/auth/refresh', { method: 'POST' })
const { token } = await res.json()
return token
}
},
// In-memory LRU cache + TTL expiration
cache: { enabled: true, ttl: 300_000 },
// Exponential retry with randomized jitter
retry: { attempts: 3, jitter: true }
})
// 2. Fully typed & deduped requests
const users = await api.get<User[]>('/users')
console.log(users.data, users.duration)
Built for Modern Apps. No Extra Libraries Needed.
Say goodbye to pasting custom 401 interceptors, retry loops, and cache maps into every new project.
Auth & Token Refresh Mutex
When 5 requests hit a 401 expired token at once, api-flow halts them, executes exactly one refresh call, and replays all 5 requests automatically with the new token. Zero race conditions.
Smart Memory LRU Cache
Zero-config in-memory caching with TTL expiration, in-flight request deduplication, and regex pattern invalidation via api.invalidateCachePattern().
Auto-Retry with Jitter
Configurable exponential backoff retries for network drops, timeouts, 429, and 5xx errors. Full jitter randomizes delays to protect backend services from retry spikes.
React Hooks Out of the Box
Import from api-flow-client/hooks: useGet, usePost, usePut, usePatch, useDelete, and useMutation with auto-cancellation on component unmount.
Next.js & SSR First-Class
Use createServerSideApi and extractServerHeaders in Next.js Server Components, App Router, Pages router, Nuxt, and Express with seamless cookie forwarding.
Pluggable Adapters
Defaults to native zero-dependency fetch. Already have an existing Axios project? Just pass adapter: 'axios' to reuse your established Axios stack without rewrite.
File Upload & Download Progress
Native progress event tracking with percentage loaded and byte counters via api.upload() and api.download().
Async Pagination Iterators
Effortlessly paginate datasets with for await (const page of api.paginate('/items')) supporting page-based and cursor-based APIs out of the box.
See api-flow-client in Action
Click the buttons below to simulate realistic network scenarios and inspect how api-flow handles them.
Clean, Expressive, and Fully Typed
Explore ready-to-paste snippets for common production patterns.
import { createApi } from 'api-flow-client'
interface User {
id: number
name: string
email: string
}
const api = createApi({
baseURL: 'https://api.example.com',
timeout: 10_000
})
// GET with generics
const res = await api.get<User[]>('/users')
console.log(res.data[0].name) // Type-safe User
// Full HTTP suite
await api.post('/users', { name: 'Alex', email: 'alex@dev.com' })
await api.put('/users/1', { name: 'Alex Updated' })
await api.patch('/users/1', { email: 'new@dev.com' })
await api.delete('/users/1')
await api.head('/users/1')
await api.options('/users')
import { createApi } from 'api-flow-client'
const api = createApi({
baseURL: 'https://api.example.com',
auth: {
// Injects "Authorization: Bearer <token>" automatically
getAccessToken: () => localStorage.getItem('access_token'),
getRefreshToken: () => localStorage.getItem('refresh_token'),
// Called ONCE when any request receives 401
refresh: async (refreshToken) => {
const response = await fetch('https://api.example.com/auth/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refreshToken })
})
const data = await response.json()
localStorage.setItem('access_token', data.accessToken)
return data.accessToken
}
}
})
import { createApi } from 'api-flow-client'
const api = createApi({
baseURL: 'https://api.example.com',
cache: {
enabled: true,
ttl: 5 * 60 * 1000, // 5 minutes TTL
maxSize: 150 // LRU limit
}
})
// 1. First call fetches over network
const u1 = await api.get('/users')
// 2. Second call returns from memory in 0ms
const u2 = await api.get('/users')
// 3. Invalidate specific URL
api.clearCache('/users')
// 4. Regex pattern bulk invalidation (NEW in v1.1.0)
api.invalidateCachePattern(/\/users\//)
import React from 'react'
import { api } from './api'
import { useGet, usePost, useDelete } from 'api-flow-client/hooks'
export function UserProfile() {
// Auto-fetches on mount, cancels on unmount
const { data, loading, error, refetch } = useGet<User>(api, '/profile')
// Mutation hooks for updates
const { mutate: updateProfile, loading: saving } = usePost(api, '/profile')
const { mutate: deleteAccount } = useDelete(api, '/profile')
if (loading) return <div>Loading user profile...</div>
if (error) return <div>Error: {error.message}</div>
return (
<div>
<h1>{data?.name}</h1>
<button onClick={() => updateProfile({ name: 'New Name' })}>Update</button>
<button onClick={() => refetch()}>Refresh</button>
</div>
)
}
// app/users/page.tsx (Next.js App Router / SSR)
import { createServerSideApi, extractServerHeaders } from 'api-flow-client'
import { headers } from 'next/headers'
export default async function UsersPage() {
const incomingHeaders = await headers()
// Forwards auth cookies & IP transparently
const api = createServerSideApi({
baseURL: process.env.INTERNAL_API_URL,
headers: extractServerHeaders({ headers: incomingHeaders })
})
const response = await api.get<User[]>('/users')
return (
<main>
<h1>Server-Rendered Users ({response.data.length})</h1>
</main>
)
}
import { api } from './api'
// 1. Page-based Async Iterator
for await (const page of api.paginate<User>('/users', { limit: 25 })) {
console.log(`Page ${page.page}:`, page.data)
if (!page.hasMore) break
}
// 2. Cursor-based Async Iterator
for await (const batch of api.cursorPaginate<LogEntry>('/logs', { limit: 100 })) {
processLogs(batch.data)
}
How Does api-flow-client Compare?
See how it stacks up against standard fetch, Axios, and Ky.
| Feature | api-flow-client | Axios | Native Fetch | Ky |
|---|---|---|---|---|
| Bundle Size (min+gzip) | 8.5 kB | ~13.5 kB | 0 kB (built-in) | ~6.2 kB |
| External Dependencies | 0 | 1 (follow-redirects) | 0 | 0 |
| 401 Token Refresh Mutex | ✓ Built-In | ✗ Manual Boilerplate | ✗ None | ✗ None |
| In-Memory LRU Cache + TTL | ✓ Built-In | ✗ Requires Plugin | ✗ None | ✗ None |
| Regex Pattern Invalidation | ✓ Built-In | ✗ None | ✗ None | ✗ None |
| Auto-Retry with Jitter | ✓ Built-In | ✗ Requires Plugin | ✗ None | ✓ Built-In |
| In-Flight Request Deduplication | ✓ Built-In | ✗ None | ✗ None | ✗ None |
| Official React Hooks Package | ✓ Built-In (useGet, usePost...) | ✗ Third Party | ✗ None | ✗ None |
| SSR Cookie & Header Extraction | ✓ Built-In | ✗ Manual | ✗ Manual | ✗ Manual |
| File Upload / Download Progress | ✓ Built-In | ✓ Built-In | ✗ Complex Streams | ✗ None |
Help Fuel api-flow-client ☕
Hi! I'm Imtiaz, the creator and maintainer of api-flow-client.
This package is 100% free, MIT licensed, and developed with passion to save developers hundreds of boilerplate hours.
If api-flow-client has helped your projects or company, consider buying me a coffee or becoming a sponsor. Every contribution keeps the project active, tested, and constantly improving!
Fuel late-night bugfixes and feature releases.
Donate $5 →Supports server costs, CI/CD testing, and documentation.
Donate $15 →For teams and organizations using api-flow in production.
Donate $50 →Common Questions
Is api-flow-client truly zero dependencies?
Yes! In default mode, api-flow-client has zero runtime dependencies. It uses the platform's native fetch and AbortController, which are standard in modern browsers, Node.js 18+, Bun, Deno, and React Native. Axios is only an optional peer dependency if you explicitly want to use the Axios adapter.
How does the 401 token refresh mutex work?
When multiple concurrent API calls receive a 401 Unauthorized status, standard clients fire multiple simultaneous refresh token requests (which can cause invalidation race conditions). api-flow-client utilizes an internal mutex queue: the first request triggers your auth.refresh() callback while subsequent failing requests are parked in a promise queue. Once the new token arrives, all queued requests are automatically re-executed with the new authorization header.
Can I use api-flow-client in Next.js Server Components?
Absolutely. api-flow-client exports createServerSideApi and extractServerHeaders, specifically designed for Next.js App Router (Server Components & Server Actions) and Pages Router. It automatically extracts incoming cookies, client IPs, and auth tokens from headers and forwards them without browser-only APIs.
How do I install the React hooks?
The React hooks are bundled inside the same package under a dedicated export path: import { useGet, useMutation, usePost, usePut, usePatch, useDelete } from 'api-flow-client/hooks'. This keeps them tree-shaken from non-React environments like pure Node.js services or Vue applications.
How can I contribute or report a bug?
Visit the official GitHub repository at github.com/imtiaz-dev-0/api-flow. Open an issue or pull request. Contributions, bug reports, and feedback are always welcome!