How to implement rate limiting per API key in Python
A simple sliding-window rate limiter that tracks request timestamps per API key and rejects requests exceeding the configured limit.
Python code
26 linesimport time
API_RATE_LIMITS = {"api_key_1": 5, "api_key_2": 3} # max requests per window
WINDOW_SECONDS = 10
class RateLimiter:
def __init__(self, limits, window):
self.limits = limits
self.window = window
self.requests = {key: [] for key in limits}
def allow(self, api_key):
now = time.time()
timestamps = self.requests.setdefault(api_key, [])
# Remove old timestamps outside the window
timestamps[:] = [t for t in timestamps if now - t < self.window]
if len(timestamps) >= self.limits.get(api_key, 0):
return False
timestamps.append(now)
return True
if __name__ == "__main__":
limiter = RateLimiter(API_RATE_LIMITS, WINDOW_SECONDS)
for key in ["api_key_1", "api_key_2", "unknown_key"]:
results = [limiter.allow(key) for _ in range(6)]
print(f"{key}: {results}")
Output
api_key_1: [True, True, True, True, True, False]
api_key_2: [True, True, True, False, False, False]
unknown_key: [True, True, True, True, True, True]
How it works
The RateLimiter keeps a list of timestamps for each API key in self.requests. On each allow call, it prunes timestamps older than the window using a list comprehension slice assignment, then checks if the count is at or above the limit. If not, it appends the current time and returns True. For unknown keys, setdefault creates an empty list and limits.get returns a default of 0, so all requests are allowed if the key is not in the limits dict. This sliding window avoids burst spikes by enforcing a rolling time window.
Common mistakes
- Forgetting to prune old timestamps, leading to premature blocking
- Using `limits[key]` without `.get()` which raises KeyError for unknown keys
- Not making timestamps thread-safe when used in concurrent environments
Variations
- Use `collections.deque` for efficient timestamp management
- Implement a fixed-window counter using a dictionary of counts and a window reset time
Real-world use cases
- Enforce per-customer API call quotas in a microservice to prevent abuse or overuse.
- Limit login attempt rates per user in a web application to slow brute-force attacks.
- Control how often a background job calls an external vendor API to stay within paid tiers.
Sponsored
More from Reliability & rate limiting
- At Least Once with Idempotent Consumer in Python medium
- Build a Rate Limiter Decorator in Python easy
- Build a queue-based admission control system in Python easy
- Chaos Inject Random Failures in Python easy
- Circuit breaker failure threshold count in Python medium
- Exactly Once Processing Dedupe Mock in Python easy
Keep learning
Related tutorials and quizzes for this topic.