What the interviewer just asked
“What are the main classes / data you’d model?”
Pull nouns from the requirements: client, API, limit, window, algorithm, result.
RateLimiterType (enum)
From hub/scripts/rate-limiter-sourced/:
public enum RateLimiterType {
TOKEN_BUCKET,
LEAKY_BUCKET,
FIXED_WINDOW,
SLIDING_WINDOW_LOG,
SLIDING_WINDOW_COUNTER
}
RateLimiterConfig (immutable + builder)
public final class RateLimiterConfig {
private final int limit;
private final long windowMs;
private final RateLimiterType type;
private final int refillRatePerSec;
public static Builder builder() { return new Builder(); }
public static final class Builder {
private int limit = 100;
private long windowMs = 1_000;
private RateLimiterType type = RateLimiterType.TOKEN_BUCKET;
private int refillRatePerSec = 10;
public Builder limit(int limit) { this.limit = limit; return this; }
public Builder windowMs(long windowMs) { this.windowMs = windowMs; return this; }
public Builder type(RateLimiterType type) { this.type = type; return this; }
public Builder refillRatePerSec(int rate) { this.refillRatePerSec = rate; return this; }
public RateLimiterConfig build() {
return new RateLimiterConfig(this);
}
}
}
Usage:
RateLimiterConfig config = RateLimiterConfig.builder()
.limit(100)
.windowMs(1_000)
.type(RateLimiterType.TOKEN_BUCKET)
.refillRatePerSec(10)
.build();
| Field | Role |
|---|---|
limit |
Max requests / tokens (capacity) |
windowMs |
Window length for window-based algos |
type |
Which algorithm to construct |
refillRatePerSec |
Token / leak rate for bucket algos |
RateLimitResult (immutable)
public final class RateLimitResult {
private final boolean allowed;
private final int remaining;
private final int totalLimit;
private final long retryAfterMs;
private final String message;
public static RateLimitResult allowed(int remaining, int totalLimit) {
return new RateLimitResult(true, remaining, totalLimit, 0L,
"OK — " + remaining + " of " + totalLimit + " remaining");
}
public static RateLimitResult rejected(int totalLimit, long retryAfterMs) {
return new RateLimitResult(false, 0, totalLimit, retryAfterMs,
"429 Too Many Requests — retry in " + retryAfterMs + " ms");
}
public boolean isAllowed() { return allowed; }
public int getRemaining() { return remaining; }
public long getRetryAfterMs() { return retryAfterMs; }
}
Callers need these for 429 responses and X-RateLimit-* headers.
What is not an entity
- clientId / api — strings at the Manager boundary; strategies key state by
clientIdinternally - HTTP layer — filter/middleware that calls
manager.hit(api, client)is integration, not the core LLD
Say this out loud
“Config and Result are immutable value objects. The algorithm type is an enum so the Factory can switch cleanly. Strategies own mutable per-client state — Config never does.”