Package Exports
- smart-api-throttle
- smart-api-throttle/react
Readme
Smart API Throttle
A lightweight, flexible, frontend-friendly API rate limiter with multiple strategies, universal async wrapper, and React hooks.
Features
- Multiple Rate Limiting Strategies: Fixed Window, Token Bucket, and Debounce
- Universal Async Wrapper: Wrap any async function with rate limiting
- Ready-to-use Adapters: Built-in support for fetch and axios
- React Hooks: Easy integration with React applications
- Smart Features: Retry on failure, exponential backoff, request queuing
- Lightweight: Zero dependencies (except axios for axios adapter)
Installation
npm install smart-api-throttleQuick Start
Basic Usage
import { SmartThrottle, presets } from 'smart-api-throttle';
// Create a limiter with fixed window strategy
const limiter = new SmartThrottle({
strategy: 'fixed-window',
maxRequests: 10,
windowMs: 60000, // 1 minute
queue: true,
retryOnFail: true,
});
// Wrap any async function
const limitedFetch = limiter.wrap(fetch);
const response = await limitedFetch('https://api.example.com/data');Using Presets
import { SmartThrottle, presets } from 'smart-api-throttle';
// Use predefined configurations
const conservativeLimiter = new SmartThrottle(presets.conservative); // 10 req/min
const moderateLimiter = new SmartThrottle(presets.moderate); // 100 req/min
const tokenBucketLimiter = new SmartThrottle(presets.tokenBucket); // 10 tokens, 1/secRate Limiting Strategies
Fixed Window
Limits requests to X calls per Y milliseconds window.
const limiter = new SmartThrottle({
strategy: 'fixed-window',
maxRequests: 100,
windowMs: 60000, // 100 requests per minute
});Token Bucket
Implements a token bucket algorithm with configurable capacity and refill rate.
const limiter = new SmartThrottle({
strategy: 'token-bucket',
capacity: 10, // Maximum tokens
refillRate: 1, // 1 token per second
});Debounce
Waits for a specified delay after the last trigger before allowing execution.
const limiter = new SmartThrottle({
strategy: 'debounce',
debounceMs: 500, // 500ms delay
});Adapters
Fetch Adapter
import { createSmartFetch } from 'smart-api-throttle';
const smartFetch = createSmartFetch({
strategy: 'fixed-window',
maxRequests: 10,
windowMs: 60000,
});
// Use like regular fetch
const response = await smartFetch.fetch('https://api.example.com/data');
// Or use convenience methods
const data = await smartFetch.get('https://api.example.com/users');
const newUser = await smartFetch.post('https://api.example.com/users', {
name: 'John Doe',
email: 'john@example.com'
});Axios Adapter
import { createSmartAxios } from 'smart-api-throttle';
const smartAxios = createSmartAxios({
strategy: 'token-bucket',
capacity: 10,
refillRate: 1,
});
// Use like regular axios
const response = await smartAxios.get('https://api.example.com/data');
const newData = await smartAxios.post('https://api.example.com/data', {
title: 'New Post',
content: 'Hello World'
});React Hooks
useSmartFetch
import { useSmartFetch } from 'smart-api-throttle/react';
function MyComponent() {
const { fetchData, isThrottled, isLoading, error } = useSmartFetch({
strategy: 'fixed-window',
maxRequests: 10,
windowMs: 60000,
}, {
onThrottle: (request) => console.log('Request throttled:', request),
onError: (error) => console.error('Request failed:', error),
});
const handleClick = async () => {
try {
const response = await fetchData('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Error:', error);
}
};
return (
<div>
<button onClick={handleClick} disabled={isThrottled || isLoading}>
{isLoading ? 'Loading...' : 'Fetch Data'}
</button>
{isThrottled && <p>Rate limited. Please wait...</p>}
{error && <p>Error: {error.message}</p>}
</div>
);
}useSmartFetchInstance
import { useSmartFetchInstance } from 'smart-api-throttle/react';
function MyComponent() {
const { fetch, isThrottled, getUsage } = useSmartFetchInstance({
strategy: 'token-bucket',
capacity: 10,
refillRate: 1,
});
const handleClick = async () => {
const response = await fetch('https://api.example.com/data');
const usage = getUsage();
console.log('Token bucket usage:', usage);
};
return (
<div>
<button onClick={handleClick} disabled={isThrottled}>
Fetch Data
</button>
<p>Throttled: {isThrottled ? 'Yes' : 'No'}</p>
</div>
);
}Advanced Features
Request Queuing
const limiter = new SmartThrottle({
strategy: 'fixed-window',
maxRequests: 5,
windowMs: 60000,
queue: true, // Enable queuing
});
// Requests will be queued when rate limit is exceeded
const promises = Array.from({ length: 10 }, (_, i) =>
limiter.wrap(fetch)(`https://api.example.com/data/${i}`)
);
// All requests will be processed in order
const responses = await Promise.all(promises);Retry with Exponential Backoff
const limiter = new SmartThrottle({
strategy: 'fixed-window',
maxRequests: 10,
windowMs: 60000,
retryOnFail: true,
maxRetries: 3,
backoffOn: [429, 503], // Retry on rate limit and service unavailable
});Custom Callbacks
const limiter = new SmartThrottle({
strategy: 'fixed-window',
maxRequests: 10,
windowMs: 60000,
onLimitReached: (request) => {
console.log('Rate limit reached for request:', request);
// Show user notification, update UI, etc.
},
onThrottle: (request) => {
console.log('Request throttled:', request);
// Handle throttled request
},
});API Reference
SmartThrottle
Constructor
new SmartThrottle(config: RateLimitConfig)Methods
wrap<T, R>(fn: (...args: T) => Promise<R>, ...args: T): Promise<R>- Wrap an async function with rate limitingcanExecute(): boolean- Check if a request can be executedgetQueueLength(): number- Get the number of queued requestsclearQueue(): void- Clear the request queuegetUsage(): any- Get current usage statistics (strategy-specific)updateConfig(config: RateLimitConfig): void- Update the limiter configuration
Configuration Options
interface RateLimitConfig {
strategy: 'fixed-window' | 'token-bucket' | 'debounce';
maxRequests?: number; // For fixed-window
windowMs?: number; // For fixed-window
capacity?: number; // For token-bucket
refillRate?: number; // For token-bucket
debounceMs?: number; // For debounce
queue?: boolean; // Enable request queuing
retryOnFail?: boolean; // Enable retry on failure
maxRetries?: number; // Maximum retry attempts
backoffOn?: number[]; // HTTP status codes to trigger backoff
onLimitReached?: (request: any) => void; // Callback when limit is reached
onThrottle?: (request: any) => void; // Callback when request is throttled
}Testing
# Run tests
npm test
# Run examples
npm run example
# Build package
npm run buildLicense
MIT