Question presented to candidate: "Add rate limiting to an Express endpoint so no single client can make more than 3 requests per minute. What exact HTTP status and headers would a client see once they exceed that, and how would you actually confirm your limiter works before shipping it?"
What a strong answer should cover:
express-rate-limit(a common, standard choice) tracks request counts per key (by default, source IP) within a configured time window, returning the standard 429 Too Many Requests status once the count exceeds the configured maximum — 📌 verified directly against a real server, not described: requests 1-3 (of amax: 3limit) returned 200, requests 4-5 returned a genuine 429.- 📌 The client-visible signal, verified directly: the standard
RateLimit-*headers (ratelimit-remaining, among others) correctly counted down with each successful request (2, then 1, then 0) — a real, checkable signal a well-behaved client can read to know how close it is to the limit, not just a black-box "sometimes I get blocked." - Rate limiting should be keyed appropriately for the actual endpoint: source IP for a general, unauthenticated endpoint; the authenticated identity (user ID, API key) for an endpoint where that is available and more precise — covered fully, with the specific brute-force rationale, in the dedicated DoS/brute-force question.
- The middleware placement matters: applying the limiter as global middleware (
app.use(limiter)) protects every route uniformly; applying it to a specific route (app.post("/login", limiter, handler)) allows a tighter, endpoint-specific limit exactly where it matters most (a login endpoint, say) without over-restricting a lightweight, low-risk endpoint elsewhere. - A precise answer names the verification step directly, matching the prompt's own request: sending more requests than the configured maximum in a real test and confirming the actual HTTP status codes returned, exactly as demonstrated here — not merely trusting the middleware's presence in the code without observing its real behavior.
- For a multi-process deployment (clustering, multiple instances — covered in its own dedicated question, with real proof each process has separate memory), the default in-memory store used by
express-rate-limitis not shared across processes — a Redis-backed store (rate-limit-redisor similar) is required for a single, consistent limit across every process/instance.
Clarifying questions expected:
- "Is this a general endpoint, or a security-sensitive one (login) needing tighter, identity-keyed limits?" — decides the specific configuration, covered further in the dedicated DoS/brute-force question.
- "Does this run as a single process, or clustered/multiple instances?" — decides whether the default in-memory store is sufficient or a shared external store is required.
Code / implementation expected: Yes — the real, measured rate-limiter behavior (200s with a counting-down header, then a genuine 429) is the concrete, convincing proof, directly answering the prompt's own request to verify it works.