feat(rate-limiting): implement cost-aware per-endpoint rate limits with Redis support#697
Open
Clinton6801 wants to merge 2 commits into
Open
feat(rate-limiting): implement cost-aware per-endpoint rate limits with Redis support#697Clinton6801 wants to merge 2 commits into
Clinton6801 wants to merge 2 commits into
Conversation
…th Redis support - Configure route-specific rate limits based on endpoint cost: * OTP/email/phone: strictest (20 req/min) - high cost external API calls * Verification endpoints: strict (30 req/min) - document processing * General API endpoints: moderate (100 req/min) - standard CRUD * Search endpoints: moderate (50 req/min) - read-only queries * Health/docs: no rate limiting - monitoring requirements - Implement Redis-backed ThrottlerModule for multi-instance compatibility * Graceful fallback to in-memory storage if Redis unavailable * Automatic reconnection with exponential backoff * Configurable via environment variables (THROTTLE_*_LIMIT, THROTTLE_*_TTL) - Add @SkipThrottle() decorator for routes that should bypass rate limiting * Applied to health checks, metrics, docs endpoints * Respects globally exempt paths via regex patterns - Create CostAwareThrottlerGuard extending NestJS ThrottlerGuard * Honors @SkipThrottle() decorator * Automatically exempts health/metrics/docs paths * Works with per-endpoint @Throttle() configurations - Apply rate limits to verification endpoints: * POST /api/v1/verification/start - @Throttle('verify-otp') * POST /api/v1/verification/resend - @Throttle('verify-otp') * POST /api/v1/verification/complete - @Throttle('verify-otp') * POST /api/v1/verification - @Throttle('verify') * POST /api/v1/verification/claims/:id/enqueue - @Throttle('verify') - Skip rate limiting on health endpoints: * GET /api/v1/health - @SkipThrottle() * GET /api/v1/health/live - @SkipThrottle() * GET /api/v1/health/ready - @SkipThrottle() * GET /api/v1/health/error - @SkipThrottle() * GET /api/v1/health/onchain - @SkipThrottle() - Add comprehensive E2E tests validating: * Strictest limits enforce on OTP endpoints (N+1 request returns 429) * Strict limits enforce on verification endpoints * Moderate limits enforce on general endpoints * Health endpoints completely bypass rate limiting * Docs endpoints completely bypass rate limiting * Limits reset after TTL window expires * Different throttle groups have independent limits * Retry-After header present on 429 responses - Update environment configuration (.env.example): * THROTTLE_VERIFY_OTP_LIMIT, THROTTLE_VERIFY_OTP_TTL * THROTTLE_VERIFY_LIMIT, THROTTLE_VERIFY_TTL * THROTTLE_GENERAL_LIMIT, THROTTLE_GENERAL_TTL * THROTTLE_SEARCH_LIMIT, THROTTLE_SEARCH_TTL * All with sensible defaults for production use - Add API documentation: * @ApiTooManyRequestsResponse() on rate-limited endpoints * Swagger shows 429 responses with proper descriptions Returns 429 Too Many Requests with Retry-After header when limits exceeded. Multi-instance deployments use Redis for shared rate limit counters. In-memory fallback available for local development. Closes Pulsefy#460
|
@Alu-card19 is attempting to deploy a commit to the Cedarich's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@Clinton6801 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Implements cost-aware, route-specific rate limiting for the Soter backend API using NestJS Throttler with Redis support for multi-instance deployments.
closes #460
Changes
🎯 New Files Created
src/common/config/rate-limit.config.tsTHROTTLE_*_LIMIT,THROTTLE_*_TTLsrc/common/decorators/skip-throttle.decorator.tssrc/common/guards/throttle.guard.tsCostAwareThrottlerGuardextends NestJSThrottlerGuard@SkipThrottle()decorator@Throttle()configurationstest/rate-limit-cost-aware.e2e-spec.ts📝 Modified Files
src/app.module.tsThrottlerModule.forRootAsync()with Redis supportCostAwareThrottlerGuardto global providerssrc/health/health.controller.ts@SkipThrottle()to all health endpoints:GET /api/v1/healthGET /api/v1/health/liveGET /api/v1/health/readyGET /api/v1/health/errorGET /api/v1/health/onchainsrc/verification/verification.controller.ts@Throttle('verify-otp', { limit: 20, ttl: 60 })to OTP endpoints:POST /api/v1/verification/startPOST /api/v1/verification/resendPOST /api/v1/verification/complete@Throttle('verify', { limit: 30, ttl: 60 })to verification endpoints:POST /api/v1/verificationPOST /api/v1/verification/claims/:id/enqueue@ApiTooManyRequestsResponse()to all decorated endpoints.env.exampleTHROTTLE_VERIFY_OTP_LIMIT=20,THROTTLE_VERIFY_OTP_TTL=60THROTTLE_VERIFY_LIMIT=30,THROTTLE_VERIFY_TTL=60THROTTLE_GENERAL_LIMIT=100,THROTTLE_GENERAL_TTL=60THROTTLE_SEARCH_LIMIT=50,THROTTLE_SEARCH_TTL=60Key Features
✅ Cost-Aware Limits: Different limits for different endpoint categories based on resource cost
✅ Multi-Instance Compatible: Redis-backed rate limiting for distributed deployments
✅ Graceful Fallback: In-memory storage if Redis unavailable (development only)
✅ Route-Specific: Apply limits per-endpoint with
@Throttle()decorator✅ Safe Exemptions: Monitoring endpoints (health, metrics, docs) never rate-limited
✅ Standards Compliant: Returns 429 with Retry-After header per HTTP standards
✅ Well Documented: Swagger integration with
@ApiTooManyRequestsResponse()✅ Comprehensive Tests: Full E2E test coverage for all scenarios
Architecture
Multi-Layer Approach:
@Throttle(),@SkipThrottle())Redis Support:
REDIS_HOST,REDIS_PORTResponse Format
429 Too Many Requests
{ "statusCode": 429, "message": "Too many requests, please try again later.", "error": "Too Many Requests" } Headers: Retry-After: 45 RateLimit-Limit: 30 RateLimit-Remaining: 0 RateLimit-Reset: 45 Testing Run Tests: npm run test:e2e -- rate-limit-cost-aware.e2e-spec.ts Test Scenarios Covered: Rate limit enforcement at each tier Health endpoint exemption TTL window reset behavior Independent limit groups Retry-After header validation Configuration Development (.env): REDIS_HOST=localhost REDIS_PORT=6379 THROTTLE_VERIFY_OTP_LIMIT=20 THROTTLE_VERIFY_LIMIT=30 THROTTLE_GENERAL_LIMIT=100 THROTTLE_SEARCH_LIMIT=50 All values configurable per environment. Breaking Changes None. This is backward compatible. Migration Notes No code changes required for existing endpoints Health endpoints now properly exempted (improvement) Verification endpoints now have stricter limits (security improvement) Environment variables optional (sensible defaults provided) Issue closes #460 Checklist ✅ Tests pass: npm run test:e2e ✅ No compilation errors ✅ Rate limits properly enforced at each tier ✅ Health endpoints bypass rate limiting ✅ Redis connection works with fallback ✅ Multi-instance deployments supported ✅ Swagger documentation includes 429 responses ✅ Environment variables documented in .env.example