hyperwiz
v1.2.2
Published
Next-generation TypeScript HTTP client with built-in retry, smart caching, and seamless authentication. Effortlessly handle API requests with advanced features for modern web development.
Readme
hyperwiz
A lightweight, flexible HTTP client library with powerful interceptors for modern web applications.
✨ Features
- 🚀 Simple Setup - One-line client creation
- 🔧 Flexible Interceptors - Add request/response/error handlers
- 🍪 Cookie Support - Works with credentials and cross-origin requests
- 🔐 Bearer Token Support - Manual or automatic token handling
- 🔄 Auto Retry - Adaptive backoff with exponential delay
- ⚡ Built-in Features - Logging, timeout, and error handling
- 🛡️ TypeScript Support - Full type safety and IntelliSense
- 🌐 Cross-Origin Ready - Built-in credentials support
- 🔒 Developer Control - You decide how to handle authentication
🚀 Quick Start
import { createClient } from 'hyperwiz';
// Simple client
const api = createClient('https://api.example.com', { logging: true });
// Make requests
const users = await api.get('/users');
const newUser = await api.post('/users', { name: 'John' });📖 Usage Examples
Basic HTTP Methods
const api = createClient('https://api.example.com');
// GET request
const users = await api.get('/users');
// POST request
const newUser = await api.post('/users', { name: 'John', email: '[email protected]' });
// PUT request
const updatedUser = await api.put('/users/1', { name: 'John Updated' });
// PATCH request
const patchedUser = await api.patch('/users/1', { email: '[email protected]' });
// DELETE request
const deleted = await api.delete('/users/1');
// HEAD request - Get headers only (useful for checking if resource exists)
const userExists = await api.head('/users/123');
// OPTIONS request - Get allowed methods for a resource (CORS preflight)
const allowedMethods = await api.options('/users');
// PURGE request - Clear cache (useful for CDNs like Cloudflare)
const cacheCleared = await api.purge('/cache/clear');Auto Retry with Adaptive Backoff
// Option 1: Simple boolean (uses default retry configuration)
const api1 = createClient('https://api.example.com', {
retry: true, // Uses default: 3 retries, 1s delay, exponential backoff
logging: true
});
// Option 2: Custom retry configuration
const api2 = createClient('https://api.example.com', {
retry: {
maxRetries: 5, // Retry up to 5 times
retryDelay: 500, // Start with 500ms delay
maxDelay: 5000, // Maximum 5 second delay
backoffMultiplier: 1.5, // Gentler backoff (1.5x instead of 2x)
retryOnStatus: [408, 429, 500, 502, 503, 504], // Retry on these status codes
retryOnNetworkError: true // Retry on network errors
},
logging: true
});
// Option 3: Disable retry
const api3 = createClient('https://api.example.com', {
retry: false, // No retry attempts
logging: true
});
// All requests automatically retry if they fail
// Retries preserve the original HTTP method, headers, and body
const data = await api1.get('/unreliable-endpoint');
const user = await api2.post('/users', { name: 'John' }); // POST retries as POSTRequest Caching (Smart In-Memory or IndexedDB)
// Option 1: Simple boolean (uses default cache configuration)
const api1 = createClient('https://api.example.com', {
cache: true, // Uses default: 5min cache, memory storage, GET requests only
logging: true
});
// Option 2: Custom cache configuration
const api2 = createClient('https://api.example.com', {
cache: {
enabled: true,
maxAge: 10 * 60 * 1000, // Cache for 10 minutes
maxSize: 50, // Maximum 50 cached items
storage: 'indexeddb', // Use IndexedDB for persistence
includeQueryParams: true, // Include query params in cache key
cacheableMethods: ['GET', 'HEAD'], // Cache GET and HEAD requests
cacheableStatusCodes: [200, 304] // Cache 200 and 304 responses
},
logging: true
});
// Option 3: Memory cache with custom settings
const api3 = createClient('https://api.example.com', {
cache: {
enabled: true,
maxAge: 2 * 60 * 1000, // Cache for 2 minutes
maxSize: 20, // Maximum 20 cached items
storage: 'memory', // Use in-memory storage (faster)
includeQueryParams: false // Ignore query params for cache key
},
logging: true
});
// Option 4: Disable caching
const api4 = createClient('https://api.example.com', {
cache: false, // No caching
logging: true
});
// First request: fetches from server
const users1 = await api1.get('/users'); // ⏳ Network request
// Second request: served from cache (instant)
const users2 = await api1.get('/users'); // 💾 Cache hit (instant)
// Cache automatically expires after maxAge
// Cache automatically evicts old entries when maxSize is reachedAdditional HTTP Methods
hyperwiz supports additional HTTP methods beyond the standard REST operations for enhanced functionality:
const api = createClient('https://api.example.com');
// HEAD - Get headers only (no body)
// Useful for checking if resource exists without downloading data
const userExists = await api.head('/users/123');
if (userExists.success) {
console.log('User exists!');
console.log('Last modified:', userExists.data.headers['last-modified']);
}
// OPTIONS - Get allowed methods for a resource
// Essential for CORS preflight requests and API discovery
const capabilities = await api.options('/users');
if (capabilities.success) {
console.log('Allowed methods:', capabilities.data.headers['allow']);
console.log('CORS headers:', capabilities.data.headers['access-control-allow-methods']);
}
// PURGE - Clear cache
// Useful for CDNs like Cloudflare, Fastly, etc.
const cacheCleared = await api.purge('/cache/clear');
if (cacheCleared.success) {
console.log('Cache cleared successfully');
}Use Cases:
- HEAD: Check resource existence, get metadata, validate URLs
- OPTIONS: CORS preflight, API discovery, check server capabilities
- PURGE: Cache invalidation, CDN management, content updates
Automatic Content-Type Detection
hyperwiz automatically detects and sets the appropriate Content-Type header for common data types:
const api = createClient('https://api.example.com');
// 📊 JSON objects/arrays - automatically sets 'application/json'
const user = await api.post('/users', { name: 'John', email: '[email protected]' });
// Content-Type: application/json
// 📝 Plain text - automatically sets 'text/plain'
const message = await api.post('/messages', 'Hello, world!');
// Content-Type: text/plain
// 🌐 HTML content - automatically sets 'text/html'
const htmlContent = await api.post('/content', '<h1>Hello</h1><p>World</p>');
// Content-Type: text/html
// 📋 XML content - automatically sets 'application/xml'
const xmlData = await api.post('/data', '<?xml version="1.0"?><root><item>value</item></root>');
// Content-Type: application/xml
// 📦 FormData - automatically sets 'multipart/form-data'
const formData = new FormData();
formData.append('name', 'John');
formData.append('file', fileInput.files[0]);
const result = await api.post('/upload', formData);
// Content-Type: multipart/form-data
// 🔗 URLSearchParams - automatically sets 'application/x-www-form-urlencoded'
const params = new URLSearchParams();
params.append('name', 'John');
params.append('email', '[email protected]');
const response = await api.post('/users', params);
// Content-Type: application/x-www-form-urlencoded
// 📁 File/Blob objects - uses their built-in type property
await api.post('/upload', file); // Uses file.type
await api.post('/upload', blob); // Uses blob.type
// 💾 Binary data - defaults to 'application/octet-stream'
const buffer = new ArrayBuffer(8);
const binary = await api.post('/binary', buffer);
// Content-Type: application/octet-stream
// 📅 Dates - automatically converts to ISO string and sets 'application/json'
const date = new Date();
const event = await api.post('/events', date);
// Content-Type: application/json, body: "2024-01-01T00:00:00.000Z"
// 🔢 Numbers/Booleans - automatically sets 'application/json'
await api.post('/config', { enabled: true, count: 42 });
// Content-Type: application/jsonSupported Data Types:
| Data Type | Content-Type | Detection Method |
|-----------|-------------|------------------|
| Objects/Arrays | application/json | Automatic |
| Strings (JSON) | application/json | Content analysis |
| Strings (HTML) | text/html | Content analysis |
| Strings (XML) | application/xml | Content analysis |
| Strings (other) | text/plain | Default |
| FormData | multipart/form-data | Type check |
| URLSearchParams | application/x-www-form-urlencoded | Type check |
| File | file.type | File properties |
| Blob | blob.type | Blob properties |
| ArrayBuffer | application/octet-stream | Default |
| TypedArrays | application/octet-stream | Default |
| Date | application/json | Automatic |
| Numbers/Booleans | application/json | Automatic |
Manual Override:
You can always manually override the Content-Type header:
// Override automatic detection
const response = await api.post('/custom', data, {
'Content-Type': 'application/custom+json'
});📁 File Upload Examples
Simple file upload with automatic Content-Type detection:
const api = createClient('https://api.example.com');
// 🖼️ Profile Picture Upload - Send actual file
const fileInput = document.getElementById('fileInput') as HTMLInputElement;
const file = fileInput.files[0];
await api.post('/profile/upload', file);
// Content-Type: image/jpeg (from file.type)
// 📄 Document Upload - Send actual file
const pdfFile = new File(['pdf content'], 'document.pdf', { type: 'application/pdf' });
await api.post('/documents/upload', pdfFile);
// Content-Type: application/pdf (from file.type)
// 🎵 Audio Upload - Send actual file
const audioBlob = new Blob(['audio content'], { type: 'audio/mpeg' });
await api.post('/audio/upload', audioBlob);
// Content-Type: audio/mpeg (from blob.type)
// 🎬 Video Upload - Send actual file
const videoFile = new File(['video content'], 'movie.mp4', { type: 'video/mp4' });
await api.post('/video/upload', videoFile);
// Content-Type: video/mp4 (from file.type)
// 📦 Multiple Files - Use FormData
const formData = new FormData();
formData.append('photo', photoFile);
formData.append('document', documentFile);
formData.append('audio', audioFile);
await api.post('/upload-multiple', formData);
// Content-Type: multipart/form-data
// 🖼️ Image Gallery Upload - Use FormData
const galleryForm = new FormData();
galleryFiles.forEach((file, index) => {
galleryForm.append(`image${index}`, file);
});
await api.post('/gallery/upload', galleryForm);
// Content-Type: multipart/form-dataHow it works:
- Step 1: Developer sends actual file objects (
File,Blob,FormData) - Step 2: Library uses the file's built-in
typeproperty - Step 3: Automatically sets the correct
Content-Typeheader - Step 4: Sends the request with proper Content-Type
- Result: Developer sends actual file content - zero configuration needed!
- Supports: All file types that have proper MIME types
Manual Bearer Token Authentication
const api = createClient('https://api.example.com');
// Developer sends token manually in each request
const profile = await api.get('/user/profile', {
'Authorization': 'Bearer your-token-here'
});
const newPost = await api.post('/posts', { title: 'Hello' }, {
'Authorization': 'Bearer your-token-here'
});Automatic Bearer Token with Interceptors
const api = createClient('https://api.example.com');
// Add token interceptor
api.addBefore((config, url) => {
const token = localStorage.getItem('token');
if (token) {
return {
...config,
headers: {
...config.headers,
'Authorization': `Bearer ${token}`
}
};
}
return config;
});
// Login (no token yet - works correctly)
const login = await api.post('/login', { username: 'admin', password: '123' });
// Store token after successful login
if (login.success) {
localStorage.setItem('token', login.data.token);
}
// Now all requests automatically include the token
const profile = await api.get('/user/profile');
const posts = await api.get('/user/posts');Cookie-Based Authentication
// For session-based authentication with cookies
const api = createClient('http://localhost:4000', {
credentials: 'include', // Important for cookies
logging: true
});
// Login - server sets session cookie
const login = await api.post('/login', { username: 'admin' });
// Subsequent requests - cookies are automatically sent
const profile = await api.get('/user/profile');
const data = await api.get('/protected-data');Custom Interceptors
const api = createClient('https://api.example.com');
// Request interceptor - runs before each request
api.addBefore((config, url) => {
console.log(`🚀 Making ${config.method} request to ${url}`);
return config;
});
// Response interceptor - runs after successful responses
api.addAfter((response, data, url) => {
console.log(`✅ Response from ${url}:`, data);
return data;
});
// Error interceptor - runs when errors occur (includes request config)
api.addErrorHandler((error, url, requestConfig) => {
console.error(`❌ Error for ${requestConfig?.method} ${url}:`, error);
return error;
});Token Refresh Logic
const api = createClient('https://api.example.com');
api.addAfter((response, data, url) => {
if (response.status === 401) {
// Token expired, refresh it
refreshToken();
}
return data;
});
// Or use error handler for more control
api.addErrorHandler((error, url, requestConfig) => {
if (isAuthError(error)) {
// Refresh token and retry the original request
return handleAuthRetry(error, url, requestConfig);
}
return error;
});Request Timeout
const api = createClient('https://api.example.com', {
timeout: 5000 // 5 second timeout
});
// All requests will timeout after 5 seconds
const data = await api.get('/slow-endpoint');⚙️ Configuration Options
const api = createClient('https://api.example.com', {
logging: true, // Enable request/response logging
timeout: 30000, // Request timeout in milliseconds
credentials: 'include', // Credentials mode for cross-origin
retry: true, // Auto retry (boolean) or retry config object
// retry: { // Custom retry configuration
// maxRetries: 3, // Maximum retry attempts
// retryDelay: 1000, // Initial delay in milliseconds
// maxDelay: 10000, // Maximum delay in milliseconds
// backoffMultiplier: 2, // Exponential backoff multiplier
// retryOnStatus: [408, 429, 500, 502, 503, 504], // HTTP status codes to retry
// retryOnNetworkError: true // Retry on network errors
// },
cache: true, // Request caching (boolean) or cache config object
// cache: { // Custom cache configuration
// enabled: true, // Enable/disable caching
// maxAge: 300000, // Cache duration in milliseconds (5 minutes)
// maxSize: 100, // Maximum number of cached items
// storage: 'memory', // Storage type: 'memory' or 'indexeddb'
// includeQueryParams: true, // Include query params in cache key
// cacheableMethods: ['GET', 'HEAD'], // HTTP methods that can be cached
// cacheableStatusCodes: [200] // Status codes that can be cached
// },
interceptors: { // Custom interceptors
before: [(config, url) => { /* ... */ }],
after: [(response, data, url) => { /* ... */ }],
onError: [(error, url, requestConfig) => { /* ... */ }]
}
});🔧 API Reference
Client Creation
// Basic client
createClient(baseUrl: string, config?: ClientConfig): HttpClient
// Public client (with logging enabled by default)
createPublicClient(baseUrl: string): HttpClientcreatePublicClient - Quick Development Setup
The createPublicClient function is a convenience method that creates an HTTP client with logging enabled by default. Perfect for development and debugging.
import { createPublicClient } from 'hyperwiz';
// Creates a client with automatic logging
const api = createPublicClient('https://api.example.com');
// Equivalent to:
// const api = createClient('https://api.example.com', { logging: true });
// All requests are automatically logged to console
const users = await api.get('/users');
// Console output: ✅ 200 https://api.example.com/users [response data]
const newUser = await api.post('/users', { name: 'John' });
// Console output: ✅ 201 https://api.example.com/users [created user data]Memory Management Functions
For long-running applications, hyperwiz provides memory management utilities to prevent memory leaks and monitor resource usage:
import {
cleanupCircuitBreakers,
cleanupRetryAttempts,
cleanupPendingRequests,
getMemoryStats
} from 'hyperwiz';cleanupCircuitBreakers()
Manually cleans up circuit breaker states that are older than 1 hour.
// Clean up circuit breaker tracking data
cleanupCircuitBreakers();
// Use in maintenance routines
setInterval(() => {
cleanupCircuitBreakers();
console.log('Circuit breakers cleaned up');
}, 30 * 60 * 1000); // Every 30 minutescleanupRetryAttempts()
Manually cleans up retry attempt tracking data older than 30 minutes.
// Clean up retry tracking data
cleanupRetryAttempts();
// Use during user session changes
function logout() {
cleanupRetryAttempts(); // Clear retry history
// ... other logout logic
}cleanupPendingRequests()
Immediately clears all pending request deduplication data.
// Clear all pending requests (useful during app shutdown)
cleanupPendingRequests();
// Use when switching contexts or during cleanup
function resetApplication() {
cleanupPendingRequests(); // Clear any ongoing requests
// ... other reset logic
}getMemoryStats()
Returns statistics about memory usage for monitoring and debugging.
// Monitor memory usage
const stats = getMemoryStats();
console.log('Memory stats:', stats);
// Output: {
// circuitBreakers: 5, // Number of active circuit breakers
// retryAttempts: 12, // Number of tracked retry attempts
// pendingRequests: 3, // Number of pending requests
// globalCacheStorages: 2 // Number of cache storage instances
// }
// Use in monitoring dashboards
function monitorMemoryUsage() {
const stats = getMemoryStats();
if (stats.pendingRequests > 50) {
console.warn('High number of pending requests:', stats.pendingRequests);
}
if (stats.circuitBreakers > 20) {
console.warn('Many circuit breakers active, consider cleanup');
}
// Send to analytics or monitoring service
analytics.track('hyperwiz_memory_stats', stats);
}Complete Memory Management Example
import {
createClient,
cleanupCircuitBreakers,
cleanupRetryAttempts,
cleanupPendingRequests,
getMemoryStats
} from 'hyperwiz';
class ApiService {
private api = createClient('https://api.example.com', {
retry: true,
cache: true,
logging: process.env.NODE_ENV === 'development'
});
constructor() {
this.startMaintenanceTimer();
}
// Periodic cleanup for memory management
private startMaintenanceTimer() {
setInterval(() => {
// Clean up old data
cleanupCircuitBreakers();
cleanupRetryAttempts();
// Monitor memory usage
const stats = getMemoryStats();
console.log('Memory cleanup completed:', stats);
// Alert if memory usage is high
if (stats.pendingRequests > 100) {
console.warn('Memory leak warning: Too many pending requests');
}
}, 10 * 60 * 1000); // Every 10 minutes
}
// Clean shutdown
async shutdown() {
console.log('Shutting down API service...');
// Force clear all pending requests
cleanupPendingRequests();
// Clean up tracking data
cleanupCircuitBreakers();
cleanupRetryAttempts();
const finalStats = getMemoryStats();
console.log('Final memory stats after cleanup:', finalStats);
}
// User logout - clear sensitive data
async logout() {
// Clear pending requests for security
cleanupPendingRequests();
console.log('User session cleaned up');
}
}
// Usage
const apiService = new ApiService();
// During app shutdown
window.addEventListener('beforeunload', () => {
apiService.shutdown();
});Note: The library automatically runs cleanup every 10 minutes, but these manual functions give you fine-grained control for specific use cases like application shutdown, user logout, or custom maintenance schedules.
HTTP Methods
// All methods return Promise<ApiResponse<T>>
api.get<T>(url: string, headers?: HeadersInit)
api.post<T>(url: string, body: unknown, headers?: HeadersInit)
api.put<T>(url: string, body: unknown, headers?: HeadersInit)
api.patch<T>(url: string, body: unknown, headers?: HeadersInit)
api.delete<T>(url: string, headers?: HeadersInit)
// Additional HTTP methods
api.head<T>(url: string, headers?: HeadersInit)
api.options<T>(url: string, headers?: HeadersInit)
api.purge<T>(url: string, headers?: HeadersInit)Interceptor Methods
// Add interceptors
api.addBefore(handler: RequestHandler)
api.addAfter(handler: ResponseHandler)
api.addErrorHandler(handler: ErrorHandler)
// Remove interceptors
api.removeBefore(handler: RequestHandler)
api.removeAfter(handler: ResponseHandler)
api.removeErrorHandler(handler: ErrorHandler)
// Clear all interceptors
api.clearInterceptors()
// Set timeout
api.setTimeout(timeoutMs: number)
// Cancel all requests
api.cancelAllRequests()🎯 How Developers Use This Library
1. Simple API Client - Most Common Use Case
import { createClient } from 'hyperwiz';
// Create a simple API client
const api = createClient('https://api.example.com', {
logging: true, // See all requests in console
retry: true // Auto-retry failed requests
});
// Use it like fetch but simpler
const users = await api.get('/users');
const newUser = await api.post('/users', { name: 'John' });
const updatedUser = await api.put('/users/1', { name: 'John Updated' });
const deleted = await api.delete('/users/1');2. Authentication with Bearer Tokens - Manual Control
const api = createClient('https://api.example.com');
// Developer manually adds tokens to each request
const profile = await api.get('/user/profile', {
'Authorization': 'Bearer your-token-here'
});
const newPost = await api.post('/posts', { title: 'Hello' }, {
'Authorization': 'Bearer your-token-here'
});3. Automatic Token Injection - Using Interceptors
const api = createClient('https://api.example.com');
// Add token interceptor - automatically adds token to all requests
api.addBefore((config, url) => {
const token = localStorage.getItem('token');
if (token) {
return {
...config,
headers: {
...config.headers,
'Authorization': `Bearer ${token}`
}
};
}
return config;
});
// Now all requests automatically include the token
const profile = await api.get('/user/profile'); // ✅ Token added automatically
const posts = await api.post('/posts', { title: 'New Post' }); // ✅ Token added automatically4. Session-Based Authentication - Cookies
// For server-side sessions (like Express.js sessions)
const api = createClient('http://localhost:4000', {
credentials: 'include', // Important: sends cookies automatically
logging: true
});
// Login - server sets session cookie
const login = await api.post('/login', { username: 'admin', password: '123' });
// All subsequent requests automatically include the session cookie
const profile = await api.get('/user/profile'); // ✅ Cookie sent automatically
const data = await api.get('/protected-data'); // ✅ Cookie sent automatically5. Reliable API with Auto-Retry - Production Ready
const api = createClient('https://api.example.com', {
retry: {
maxRetries: 3, // Retry failed requests up to 3 times
retryDelay: 1000, // Start with 1 second delay
maxDelay: 10000, // Maximum 10 second delay
backoffMultiplier: 2, // Double the delay each retry
retryOnStatus: [408, 429, 500, 502, 503, 504], // Retry on these errors
retryOnNetworkError: true // Retry on network failures
},
timeout: 10000, // 10 second timeout
logging: true // Log all requests and retries
});
// This request will automatically retry if it fails
// Retries preserve the original method (POST), body, and headers
const result = await api.post('/orders', {
productId: 123,
quantity: 2
});6. React Hook Pattern - Modern React Apps
import { useState, useCallback } from 'react';
import { createClient } from 'hyperwiz';
function useApi() {
const [api] = useState(() => createClient('https://api.example.com', {
retry: true,
logging: process.env.NODE_ENV === 'development'
}));
const login = useCallback(async (credentials: any) => {
const response = await api.post('/auth/login', credentials);
if (response.success) {
localStorage.setItem('auth-token', response.data.token);
}
return response;
}, [api]);
const logout = useCallback(() => {
localStorage.removeItem('auth-token');
}, []);
const getProfile = useCallback(async () => {
const token = localStorage.getItem('auth-token');
return await api.get('/user/profile', {
'Authorization': `Bearer ${token}`
});
}, [api]);
return { api, login, logout, getProfile };
}
// Usage in component
function ProfileComponent() {
const { getProfile } = useApi();
const handleLoadProfile = async () => {
const profile = await getProfile();
if (profile.success) {
console.log('Profile:', profile.data);
}
};
}7. API Service Class - Organized Code
class UserAPI {
private api = createClient('https://api.example.com', {
retry: true,
logging: true
});
constructor() {
// Add authentication interceptor
this.api.addBefore((config, url) => {
const token = localStorage.getItem('token');
if (token) {
config.headers = {
...config.headers,
'Authorization': `Bearer ${token}`
};
}
return config;
});
// Add error logging
this.api.addErrorHandler((error, url, requestConfig) => {
console.error(`API Error: ${requestConfig?.method} ${url}`, error);
return error;
});
}
async getUsers() {
const response = await this.api.get('/users');
return response.success ? response.data : [];
}
async createUser(userData: any) {
const response = await this.api.post('/users', userData);
return response.success ? response.data : null;
}
async updateUser(id: string, userData: any) {
const response = await this.api.put(`/users/${id}`, userData);
return response.success ? response.data : null;
}
async deleteUser(id: string) {
const response = await this.api.delete(`/users/${id}`);
return response.success;
}
}
// Usage
const userAPI = new UserAPI();
const users = await userAPI.getUsers();
const newUser = await userAPI.createUser({ name: 'John', email: '[email protected]' });8. E-commerce with Different Retry Strategies
class EcommerceAPI {
// Critical operations (payments, orders) - aggressive retry
private criticalApi = createClient('https://api.shop.com', {
retry: {
maxRetries: 5, // More retries for critical operations
retryDelay: 500, // Start with shorter delay
maxDelay: 5000, // Shorter max delay
backoffMultiplier: 1.5, // Gentler backoff
retryOnStatus: [500, 502, 503, 504], // Only retry server errors
retryOnNetworkError: true
}
});
// Normal operations (products, reviews) - standard retry
private normalApi = createClient('https://api.shop.com', {
retry: {
maxRetries: 3, // Standard retries
retryDelay: 1000, // Standard delay
maxDelay: 10000, // Standard max delay
backoffMultiplier: 2, // Standard backoff
retryOnStatus: [408, 429, 500, 502, 503, 504],
retryOnNetworkError: true
}
});
// Critical operation - aggressive retry
async createOrder(orderData: any) {
return await this.criticalApi.post('/orders', orderData);
}
// Normal operation - standard retry
async getProducts() {
return await this.normalApi.get('/products');
}
async getProductReviews(productId: string) {
return await this.normalApi.get(`/products/${productId}/reviews`);
}
}9. Custom Error Handling with Retry
const api = createClient('https://api.example.com', {
retry: true,
logging: true
});
// Custom error handling
api.addErrorHandler((error, url, requestConfig) => {
// Log specific errors
if (requestConfig?.method === 'POST' && url.includes('/orders')) {
console.error('Order creation failed:', error);
}
// Handle specific error types
if (isRateLimitError(error)) {
console.warn('Rate limit hit, will retry with backoff');
}
return error; // Let the retry mechanism handle it
});
function isRateLimitError(error: unknown): boolean {
return typeof error === 'object' && error !== null &&
'status' in error && (error as any).status === 429;
}10. Smart Caching for Performance
// E-commerce app with different caching strategies
class ProductAPI {
// Product catalog - long cache (rarely changes)
private catalogApi = createClient('https://api.shop.com', {
cache: {
enabled: true,
maxAge: 30 * 60 * 1000, // 30 minutes
maxSize: 100,
storage: 'indexeddb', // Persistent across sessions
cacheableMethods: ['GET', 'HEAD'],
cacheableStatusCodes: [200]
}
});
// User-specific data - short cache (changes frequently)
private userApi = createClient('https://api.shop.com', {
cache: {
enabled: true,
maxAge: 2 * 60 * 1000, // 2 minutes
maxSize: 20,
storage: 'memory', // Fast access
cacheableMethods: ['GET', 'HEAD'],
cacheableStatusCodes: [200]
}
});
// Real-time data - no cache
private realtimeApi = createClient('https://api.shop.com', {
cache: false, // Always fresh data
retry: true
});
// Product catalog (cached for 30 minutes)
async getProducts(category?: string) {
const url = category ? `/products?category=${category}` : '/products';
return await this.catalogApi.get(url);
}
// User cart (cached for 2 minutes)
async getUserCart() {
return await this.userApi.get('/user/cart', {
'Authorization': `Bearer ${localStorage.getItem('token')}`
});
}
// Stock levels (no cache, always fresh)
async getStockLevels(productId: string) {
return await this.realtimeApi.get(`/products/${productId}/stock`);
}
// Clear cache when user logs out
clearUserCache() {
// Note: In a real app, you'd want to clear specific cache entries
// This is a simplified example
console.log('User logged out, cache will expire naturally');
}
}
// Usage
const productAPI = new ProductAPI();
// First load: fetches from server
const products = await productAPI.getProducts('electronics'); // ⏳ Network request
// Subsequent loads: instant from cache
const products2 = await productAPI.getProducts('electronics'); // 💾 Cache hit (instant)
// User cart: cached briefly for performance
const cart = await productAPI.getUserCart(); // ⏳ Network request
const cart2 = await productAPI.getUserCart(); // 💾 Cache hit (instant)
// Stock levels: always fresh
const stock = await productAPI.getStockLevels('123'); // ⏳ Always network request12. Advanced Caching with Cache Management
import { createClient } from 'hyperwiz';
// Create client with custom cache storage
const api = createClient('https://api.example.com', {
cache: {
enabled: true,
maxAge: 5 * 60 * 1000, // 5 minutes
maxSize: 50,
storage: 'indexeddb', // Persistent storage
includeQueryParams: true,
cacheableMethods: ['GET', 'HEAD'],
cacheableStatusCodes: [200]
},
logging: true
});
// Cache management functions
class CacheManager {
static async clearCache() {
// Clear all cached responses
const cacheStorage = new IndexedDBCacheStorage();
await cacheStorage.clear();
console.log('Cache cleared');
}
static async getCacheStats() {
const cacheStorage = new IndexedDBCacheStorage();
const keys = await cacheStorage.keys();
console.log(`Cache contains ${keys.length} items:`, keys);
return keys;
}
static async removeExpiredCache() {
const cacheStorage = new IndexedDBCacheStorage();
const keys = await cacheStorage.keys();
const now = Date.now();
for (const key of keys) {
const cached = await cacheStorage.get(key);
if (cached && (now - cached.timestamp) > 5 * 60 * 1000) {
await cacheStorage.delete(key);
console.log(`Removed expired cache: ${key}`);
}
}
}
}
// Usage
const users = await api.get('/users'); // First request: network
const users2 = await api.get('/users'); // Second request: cache
// Manage cache
await CacheManager.getCacheStats(); // See what's cached
await CacheManager.removeExpiredCache(); // Clean up expired entries
await CacheManager.clearCache(); // Clear all cache🎯 Real-World Examples
React Hook with Token Management
import { useState } from 'react';
import { createClient } from 'hyperwiz';
function useApi() {
const [api] = useState(() => createClient('https://api.example.com'));
const login = async (credentials: any) => {
const response = await api.post('/auth/login', credentials);
if (response.success) {
localStorage.setItem('auth-token', response.data.token);
}
return response;
};
const logout = () => {
localStorage.removeItem('auth-token');
};
const makeAuthenticatedRequest = async (url: string, token: string) => {
return await api.get(url, {
'Authorization': `Bearer ${token}`
});
};
return { api, login, logout, makeAuthenticatedRequest };
}API Service Class
class UserAPI {
private api = createClient('https://api.example.com', { logging: true });
constructor() {
// Add authentication interceptor
this.api.addBefore((config, url) => {
const token = localStorage.getItem('token');
if (token) {
config.headers = { ...config.headers, 'Authorization': `Bearer ${token}` };
}
return config;
});
}
async getUsers() {
const response = await this.api.get('/users');
return response.success ? response.data : [];
}
async createUser(userData: any) {
const response = await this.api.post('/users', userData);
return response.success ? response.data : null;
}
async updateUser(id: string, userData: any) {
const response = await this.api.put(`/users/${id}`, userData);
return response.success ? response.data : null;
}
}E-commerce with Retry Strategies
