@wysdj/afetch
v1.0.3
Published
A lightweight, zero-dependency fetch wrapper with axios-like API, interceptors, timeout, upload progress and more.
Maintainers
Readme
afetch
🚀 A lightweight, zero-dependency fetch wrapper with axios-like API. Interceptors, timeout, upload progress, cancellation — all built-in.
一个轻量、无依赖、行为对齐 axios 的 fetch 封装,适用于小中大型前端项目。
✨ Features
- 🪶 Zero dependencies — No axios, no XHR polyfill, just native fetch
- 🔄 Axios-like API —
get,post,put,delete,patch - 🎯 Interceptors — Request & Response (fulfilled / rejected)
- ⏱ Timeout & Cancellation — Powered by
AbortController - 📊 Upload progress — XHR fallback (works in Safari too!)
- ❌ HTTP errors (404/500) auto-reject — No more
.okchecks - 📦 Tree-shakeable — ESM + CJS dual build
- 🏷 Full TypeScript support — Generics, types included
📦 Installation
npm install @wysdj/afetch
# or
yarn add @wysdj/afetch
# or
pnpm add @wysdj/afetch🚀 Quick Start
import { createFetch } from 'afetch';
const request = createFetch({
baseURL: 'https://api.example.com',
timeout: 10000,
headers: {
'Authorization': 'Bearer token123'
}
});
// GET
const users = await request.get('/users', { params: { page: 1 } });
// POST
const result = await request.post('/users', { name: 'Tom' });📖 API Reference
createFetch(config?)
Create a new afetch instance.
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| baseURL | string | '' | Base URL for all requests |
| timeout | number | 0 (no timeout) | Default timeout in ms |
| headers | Record<string, string> | {} | Default headers |
Request Methods
request.get<T>(url, config?)
request.post<T>(url, data?, config?)
request.put<T>(url, data?, config?)
request.delete<T>(url, config?)
request.patch<T>(url, data?, config?)All methods support generic typing:
interface User {
id: number;
name: string;
}
const user = await request.get<User>('/user/1');
// user is fully typed ✅FetchRequestConfig
| Option | Type | Description |
|--------|------|-------------|
| url | string | Endpoint path |
| method | string | HTTP method |
| params | object | URL query parameters |
| body | any | Request body (auto-stringified unless FormData) |
| headers | object | Request headers |
| timeout | number | Per-request timeout (ms) |
| signal | AbortSignal | AbortController signal |
| onUploadProgress | (percent: number) => void | Upload progress callback |
🔄 Interceptors
Request Interceptor
request.interceptors.request.use(config => {
config.headers!.Authorization = `Bearer ${getToken()}`;
return config;
});Response Interceptor
// Fulfilled
request.interceptors.response.use(
data => {
// Unwrap common response format
return data.data ?? data;
},
// Rejected
error => {
if (error.status === 401) {
redirectToLogin();
}
return Promise.reject(error);
}
);⏱ Timeout & Cancellation
Timeout
// Global
const request = createFetch({ timeout: 5000 });
// Per-request
await request.get('/slow', { timeout: 2000 });Cancellation
const controller = new AbortController();
request.get('/long-task', { signal: controller.signal })
.catch(err => console.log(err.message)); // Request timeout
// Cancel anytime
controller.abort();📊 Upload with Progress
const formData = new FormData();
formData.append('file', fileInput.files[0]);
await request.post('/upload', formData, {
headers: {}, // Let browser set Content-Type
onUploadProgress(percent) {
console.log(`Uploading: ${percent}%`);
}
});⚠️ Upload progress uses XHR fallback internally, so it works in all browsers including Safari.
❌ Error Handling
try {
await request.get('/not-found');
} catch (err: any) {
console.log(err.status); // 404
console.log(err.message); // "Not Found"
console.log(err.data); // Response body
}All HTTP errors (4xx, 5xx) are automatically rejected — no manual res.ok check needed.
🆚 Comparison with axios
| Feature | afetch | axios | |---------|-----------|-------| | Bundle size | ~3KB gzipped | ~13KB gzipped | | Dependencies | 0 | 1 (follow-redirects in Node) | | Interceptors | ✅ | ✅ | | Timeout | ✅ | ✅ | | Cancellation | ✅ (AbortController) | ✅ (AbortController / CancelToken) | | Upload progress | ✅ (XHR fallback) | ✅ (native) | | HTTP errors → reject | ✅ | ✅ | | SSR / Node support | ✅ (Node 18+) | ✅ | | Browser support | Modern + Safari | All | | TypeScript | ✅ (built-in) | ✅ (@types/axios) |
🎯 When to Use afetch
✅ Great for:
- New projects /重构
- Lightweight apps, libraries, SDKs
- Edge runtime (Cloudflare Workers, Vercel Edge)
- Teams who prefer zero-dependency
- Projects already using React Query / SWR / TanStack Query
⚠️ Consider axios if:
- You need IE11 support
- Heavy reliance on advanced upload/download features
- Large team already standardized on axios
📄 License
MIT © wangyashun
⭐ Show your support
Give a ⭐️ if this project helped you!
