JAVASCRIPT
Simple Rate Limiter for Outgoing API Requests
Implement a basic rate limiter in Node.js to control the frequency of outgoing API calls, preventing your application from exceeding external service rate limits.
// A simple in-memory queue and rate limiter
class ApiRateLimiter {
constructor(requestsPerInterval, intervalMs) {
this.requestsPerInterval = requestsPerInterval;
this.intervalMs = intervalMs;
this.queue = [];
this.timestamps = []; // Stores timestamps of recent requests
this.isProcessing = false;
console.log(`Rate Limiter initialized: ${requestsPerInterval} requests/${intervalMs / 1000}s`);
}
// Add a request function to the queue
addRequest(requestFn) {
return new Promise((resolve, reject) => {
this.queue.push({ requestFn, resolve, reject });
this.processQueue();
});
}
async processQueue() {
if (this.isProcessing) {
return;
}
this.isProcessing = true;
while (this.queue.length > 0) {
// Clean up old timestamps
const now = Date.now();
this.timestamps = this.timestamps.filter(ts => ts > now - this.intervalMs);
if (this.timestamps.length < this.requestsPerInterval) {
const { requestFn, resolve, reject } = this.queue.shift(); // Get next request
this.timestamps.push(now); // Mark this request as sent
try {
const result = await requestFn(); // Execute the actual API call
resolve(result);
} catch (error) {
reject(error);
}
} else {
// Rate limit hit, wait until next slot is available
const timeToWait = this.intervalMs - (now - this.timestamps[0]);
console.log(`Rate limit hit. Waiting for ${timeToWait}ms...`);
await new Promise(res => setTimeout(res, timeToWait + 50)); // Add a small buffer
}
}
this.isProcessing = false;
}
}
// Example Usage:
const myRateLimiter = new ApiRateLimiter(5, 1000); // 5 requests per second
async function makeApiCall(id) {
return myRateLimiter.addRequest(async () => {
console.log(`[${new Date().toLocaleTimeString()}] Making API call ${id}...`);
// Simulate an API call
return new Promise(resolve => setTimeout(() => {
console.log(`[${new Date().toLocaleTimeString()}] API call ${id} complete.`);
resolve(`Response for call ${id}`);
}, Math.random() * 500)); // Simulate variable API response time
});
}
// Make some requests quickly to test the limiter
// for (let i = 1; i <= 15; i++) {
// makeApiCall(i).then(result => console.log(result)).catch(console.error);
// }
// After a delay, make more requests
// setTimeout(() => {
// for (let i = 16; i <= 20; i++) {
// makeApiCall(i).then(result => console.log(result)).catch(console.error);
// }
// }, 3000);
How it works: This Node.js snippet provides a basic in-memory rate limiter that controls the frequency of outgoing API requests. It maintains a queue of pending requests and a list of timestamps for recently made requests. Before executing a new request, it checks if the configured `requestsPerInterval` limit has been reached within the `intervalMs`. If the limit is hit, it pauses execution for the calculated duration until a slot becomes available, preventing the application from overwhelming external APIs and hitting their rate limits.