patterntypescriptModerate
Rate Limiting Headers: Use X-RateLimit-* headers for transparent quota communication
Viewed 0 times
rate-limitheadersquota429retry-afterthrottlex-ratelimit
Error Messages
Problem
APIs that enforce rate limits without communicating quota state force clients to handle 429 errors reactively. Clients have no visibility into how many requests remain and when the window resets.
Solution
Return standard rate limit headers on every response: X-RateLimit-Limit (total requests allowed per window), X-RateLimit-Remaining (requests left in current window), X-RateLimit-Reset (Unix timestamp when window resets). On 429, also include Retry-After.
Why
Transparent quota headers let well-behaved clients proactively throttle themselves, reducing 429 errors. They also help developers understand their consumption patterns during integration.
Gotchas
- The RateLimit header format is being standardized (RFC 9110 draft) — consider also emitting the draft-standard RateLimit-Policy header for forward compatibility.
- X-RateLimit-Reset as Unix epoch vs HTTP date — pick one and document it.
- Ensure headers are emitted even on cache hits if the rate limit window is per-user.
Code Snippets
Rate limit header middleware
async function rateLimitMiddleware(req: Request, res: Response, next: NextFunction) {
const key = req.user?.id ?? req.ip
const limit = await getRateLimit(key)
res.setHeader('X-RateLimit-Limit', limit.max)
res.setHeader('X-RateLimit-Remaining', limit.remaining)
res.setHeader('X-RateLimit-Reset', limit.resetAt)
if (limit.remaining <= 0) {
res.setHeader('Retry-After', limit.retryAfterSeconds)
return res.status(429).json({
error: { code: 'RATE_LIMIT_EXCEEDED', retryAfter: limit.retryAfterSeconds }
})
}
next()
}Revisions (0)
No revisions yet.