/**
* Configures API endpoints with rate limiting.
*
* @param {object} config - Configuration object containing API endpoint definitions and rate limits.
* @returns {object} - An object containing functions to access API endpoints with rate limiting.
*/
function configureAPIs(config) {
const apiEndpoints = {}; // Store API endpoints with rate limits
// Validate config
if (!config || typeof config !== 'object') {
console.error("Invalid config provided. Must be an object.");
return { };
}
for (const endpointName in config) {
if (config.hasOwnProperty(endpointName)) {
const endpoint = config[endpointName];
if (typeof endpoint !== 'object' || !endpoint.url || !endpoint.rateLimit) {
console.warn(`Invalid endpoint configuration for ${endpointName}. Skipping.`);
continue;
}
apiEndpoints[endpointName] = {
url: endpoint.url,
rateLimit: endpoint.rateLimit,
tokens: endpoint.rateLimit.max, // Initialize tokens
resetTime: null,
lock: false, // prevent concurrent requests
acquire: async () => {
// Wait until tokens are available
while (apiEndpoints[endpointName].lock) {
await new Promise(resolve => setTimeout(resolve, 10)); // Small delay
}
if (apiEndpoints[endpointName].tokens <= 0) {
const now = Date.now();
const nextAvailable = apiEndpoints[endpointName].resetTime || now + (1000 / apiEndpoints[endpointName].rateLimit.refetchInterval);
if (nextAvailable > now) {
// Wait until tokens are refilled
await new Promise(resolve => setTimeout(resolve, nextAvailable - now));
}
}
apiEndpoints[endpointName].tokens--;
apiEndpoints[endpointName].lock = true;
return;
},
release: () => {
apiEndpoints[endpointName].tokens++;
apiEndpoints[endpointName].lock = false;
},
fetch: async (data = {}) => {
await apiEndpoints[endpointName].acquire(); // Acquire a token before fetching
try {
const response = await fetch(apiEndpoints[endpointName].url, {
method: 'POST', // or GET, PUT, DELETE, etc.
headers: {
'Content-Type': 'application/json',
// Add other headers as needed
},
body: JSON.stringify(data), // or other data format
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = await response.json();
return json;
} catch (error) {
console.error(`Error fetching from ${endpointName}:`, error);
throw error; // Re-throw the error
} finally {
apiEndpoints[endpointName].release(); // Release the token after fetching
}
},
resetTokens: () => {
apiEndpoints[endpointName].tokens = apiEndpoints[endpointName].rateLimit.max;
apiEndpoints[endpointName].resetTime = null;
}
};
}
}
return { apiEndpoints };
}
export default configureAPIs;
Add your comment