SafeFetch is a TypeScript-first HTTP client with built-in retry logic, timeout handling, and Next.js App Router support.
- βοΈ Retry logic for safe HTTP methods (GET, PUT)
- β±οΈ Timeout protection with AbortController
- π§Ύ Full TypeScript support with excellent IntelliSense & JSDoc
- π Type inference logging for development
- π JSON & FormData support
- π§ Next.js App Router compatible - revalidate, cache, tags
- π Optional Basic Auth from environment variables
- π Query parameters with automatic URL encoding
- π― Consistent error handling with typed responses
# .env.local
BASE_URL=https://api.your-domain.com
AUTH_USERNAME=your_username
AUTH_PASSWORD=your_password
Simply copy the SafeFetch code into your project (e.g., lib/api.ts
or utils/safe-fetch.ts
).
import apiRequest from './lib/api';
interface User {
id: number;
name: string;
email: string;
}
// GET request
const result = await apiRequest<User[]>('GET', '/users');
if (result.success) {
console.log(result.data); // Full TypeScript intellisense
} else {
console.error(result.error);
}
const newUser = await apiRequest<User>('POST', '/users', {
data: {
name: 'John Doe',
email: 'john@example.com'
}
});
const result = await apiRequest<Product[]>('GET', '/products', {
params: { category: 'electronics', limit: 10 },
retries: 3,
timeout: 15000,
cache: 'force-cache',
revalidate: 3600,
tags: ['products']
});
const formData = new FormData();
formData.append('file', file);
const result = await apiRequest<{url: string}>('POST', '/upload', {
data: formData,
timeout: 60000
});
SafeFetch provides excellent IntelliSense & JSDoc support with:
- Response type inference -
result.data
is automatically typed - Request body validation - TypeScript validates your data structure
- Options autocomplete - Full IDE support for configuration options
- JSDoc documentation - Hover tooltips with parameter descriptions
// TypeScript knows result.data is User[] when success is true
const users = await apiRequest<User[]>('GET', '/users');
apiRequest<ResponseType, RequestType>(method, endpoint, options?)
interface RequestOptions<TBody> {
data?: TBody; // Request body
params?: Record<string, string | number | boolean | null | undefined>; // Query parameters
retries?: number; // Default: 1
timeout?: number; // Default: 30000ms
cache?: RequestCache; // Fetch cache strategy
revalidate?: number | false; // Next.js ISR revalidation time
tags?: string[]; // Next.js cache tags
headers?: Record<string, string>; // Custom headers
logTypes?: boolean; // Log inferred types (dev only)
transform?<T>(data: T): T; // Transform response data before returning
onError?: (error: ApiError, attempt: number) => void; // Custom error handler
shouldRetry?: (error: ApiError, attempt: number) => boolean; // Custom retry condition
allowedHosts?: string[]; // Allowed hosts for SSRF protection
maxResponseSize?: number; // Maximum response size in bytes
}
type ApiResponse<T> =
| { success: true; status: number; data: T; headers: Headers }
| { success: false; status: number; error: ApiError; data: null };
// Server Component
export default async function Page() {
const products = await apiRequest<Product[]>('GET', '/products', {
revalidate: 300,
tags: ['products']
});
return <div>{/* render products */}</div>;
}
// Server Action
'use server';
export async function createProduct(formData: FormData) {
const result = await apiRequest('POST', '/products', {
data: Object.fromEntries(formData)
});
if (result.success) {
revalidateTag('products');
}
return result;
}
For comprehensive examples including CRUD operations, authentication, error handling, and advanced patterns, see Examples.
Works in all modern environments that support:
- Fetch API
- AbortController
- Promises
- URL constructor
Compatible with:
- β Next.js 13+ (App Router)
- β React 18+
- β Node.js 18+
- β All modern browsers
This project is licensed under the BSD 3-Clause License. Attribution to Bharathi4real is required. See LICENSE for details.
SafeFetch - Simple, typed, reliable HTTP requests for modern TypeScript applications.