Cursor prompt to add rate limiting to an API
Rate limiting sounds like one middleware call until you meet proxies, shared IPs, and login endpoints that need tighter caps than the rest. This prompt has Cursor implement a sliding window limiter with correct 429 responses, Retry-After headers, and health check exemptions, then prove threshold and reset behavior with tests against your routes.
Last updated
Add rate limiting to the API in this codebase. Implement a sliding window limiter keyed on authenticated user id when present, falling back to client IP taken from the leftmost trusted X-Forwarded-For entry only when a proxy is configured. Store counters in Redis if the project already runs it; otherwise use an in-memory store and flag in a comment that it will not work across multiple instances. Default to 100 requests per minute per key, overridable per route, with stricter caps on login and password reset endpoints to slow credential stuffing. Return 429 with Retry-After and RateLimit-Remaining headers, and exclude health check routes. Write tests that fire requests past the threshold, assert the 429 and header values, confirm the window resets, then run the full suite.
Questions about this prompt
Why does the prompt care where the client IP comes from?
Because X-Forwarded-For is client-controlled unless a trusted proxy sets it, and a limiter keyed on a spoofable header can be bypassed or weaponized to lock out other users. The prompt keys on user id first and only trusts the header when a proxy is actually configured.
Cursor put the counters in memory. Is that a problem?
For a single process it is fine, and the prompt has the agent flag the limitation in a comment. Once you run two or more instances behind a load balancer, each keeps separate counts and the effective limit multiplies. Move the store to Redis at that point; the tests should pass unchanged.
How do I set different limits for different routes?
The prompt requests per-route overrides, so state your numbers, for example 5 per minute on POST /auth/login and 300 on public reads. Concrete figures per route stop the agent from applying one global limit everywhere.