UNPKG

dynamic-rate-limiter-middleware

Version:

Intelligent rate limiting middleware with MongoDB integration and caching for Node.js applications

168 lines (145 loc) 3.85 kB
const mongoose = require('mongoose'); const hitSchema = new mongoose.Schema({ // API endpoint information endpoint: { type: String, required: true, index: true }, method: { type: String, required: true, enum: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], default: 'GET' }, // Hit tracking hits: { type: Number, default: 0, min: 0 }, lastHit: { type: Date, default: Date.now }, dailyLimit: { type: Number, required: true, default: 500 }, // Response caching responseData: { type: mongoose.Schema.Types.Mixed, default: null }, cacheExpiry: { type: Date, default: null }, // Traffic pattern analysis trafficPattern: { peak: { type: Number, default: 0 }, offPeak: { type: Number, default: 0 }, timezone: { type: String, default: 'UTC' } }, // Error tracking errors: [{ timestamp: { type: Date, default: Date.now }, code: String, message: String }], // Analytics successRate: { type: Number, default: 100, min: 0, max: 100 }, averageResponseTime: { type: Number, default: 0 } }, { timestamps: true, collection: 'hits' }); // Index for efficient querying hitSchema.index({ endpoint: 1, method: 1 }); hitSchema.index({ lastHit: 1 }); // Method to check if daily limit is reached hitSchema.methods.isLimitReached = function() { const today = new Date(); const lastHitDate = this.lastHit; // Reset hits if it's a new day if (lastHitDate && lastHitDate.getDate() !== today.getDate()) { this.hits = 0; return false; } return this.hits >= this.dailyLimit; }; // Method to update hit count and analytics hitSchema.methods.recordHit = async function(responseTime, isSuccess) { // Update hit count this.hits += 1; this.lastHit = new Date(); // Update success rate const totalHits = this.hits; const currentSuccessRate = this.successRate; this.successRate = ((currentSuccessRate * (totalHits - 1)) + (isSuccess ? 100 : 0)) / totalHits; // Update average response time this.averageResponseTime = ((this.averageResponseTime * (totalHits - 1)) + responseTime) / totalHits; // Update traffic pattern const hour = this.lastHit.getHours(); if (hour >= 9 && hour < 17) { // Peak hours (9 AM - 5 PM) this.trafficPattern.peak += 1; } else { this.trafficPattern.offPeak += 1; } return this.save(); }; // Method to record errors hitSchema.methods.recordError = function(code, message) { this.errors.push({ timestamp: new Date(), code, message }); if (this.errors.length > 100) { // Keep only last 100 errors this.errors = this.errors.slice(-100); } return this.save(); }; // Static method to get analytics hitSchema.statics.getAnalytics = async function(endpoint) { const pipeline = [ { $match: endpoint ? { endpoint } : {} }, { $group: { _id: '$endpoint', totalHits: { $sum: '$hits' }, averageSuccessRate: { $avg: '$successRate' }, averageResponseTime: { $avg: '$averageResponseTime' }, peakHits: { $sum: '$trafficPattern.peak' }, offPeakHits: { $sum: '$trafficPattern.offPeak' } } } ]; return this.aggregate(pipeline); }; const Hit = mongoose.model('Hit', hitSchema); module.exports = Hit;