Sliding-Window Rate Limiter in proxy.ts
Hard · Proxy
Protect your API routes with a rate limiter in proxy.ts (the Next.js 16 name for middleware). It runs before the route handler: to let a request through it returns NextResponse.next(), to block it it returns its own response.
Implement createRateLimiter({ limit, windowMs }), which returns proxy(request, now) (the time is passed in so the tests are stable). The starter's next(headers) mimics NextResponse.next().
- Only /api and paths under /api/ are limited (/apiary is not). Other paths return next() without rate-limit headers.
- The client is the first entry of x-forwarded-for (trimmed; proxies append their own addresses). If it is missing or empty, use x-real-ip (trimmed), else "unknown". Each client has its own limit.
- Sliding window log: remember the time of every allowed request per client. A request counts while now - time < windowMs; older ones are forgotten.
- If the client already has limit requests in the window, respond with 429 and the JSON { "error": "Too many requests" } (Response.json(body, { status, headers })), with the headers Retry-After (seconds until the oldest counted request leaves the window, rounded up) and X-RateLimit-Remaining: 0. Blocked requests are not recorded.
- Otherwise record the request and return next({ "X-RateLimit-Remaining": String(limit - count) }), where count includes this request.
In production this state must live in a shared store such as Redis: proxy code can run on many separate instances, so an in-memory Map only works as an example.