A robust, highly extensible, and thread-safe API Rate Limiter built in Java. This system is designed from the ground up adhering strictly to SOLID Principles and enterprise Design Patterns.
It acts as a gateway interceptor, validating if incoming HTTP requests exceed the configured thresholds using highly optimized mathematical algorithms before allowing traffic to hit the core database or application logic.
The system architecture heavily utilizes Interface Segregation to keep the storage layer decoupled from the math layer, while employing Factories and Builders to manage object creation.
classDiagram
%% ================= Interfaces & Implementations =================
class RateLimiter {
<<interface>>
+tryAcquire(request: Request): Response
}
class ApplicationRateLimiter {
-algorithm: RateLimitAlgorithm
-keyExtractor: KeyExtractor
-applicationRepository: ApplicationRepository
+tryAcquire(request: Request): Response
}
RateLimiter <|.. ApplicationRateLimiter : Implements
%% ================= Request & Response =================
class Request {
<<interface>>
+getIpAddress() String
+getUserId() String
+getLocation() String
+getEndpoint() String
}
class HttpRequest
Request <|.. HttpRequest : Implements
class Response~T~ {
<<interface>>
+isRateLimitExceeded() boolean
+getResponse() T
}
class HttpResponse
Response <|.. HttpResponse : Implements
%% ApplicationRateLimiter Aggregations & Dependencies
ApplicationRateLimiter o-- RateLimitAlgorithm : Aggregation (Injects)
ApplicationRateLimiter o-- KeyExtractor : Aggregation (Injects)
ApplicationRateLimiter o-- ApplicationRepository : Aggregation (Injects)
ApplicationRateLimiter ..> Request : Associates
ApplicationRateLimiter ..> Response : Creates
%% ================= Algorithms =================
class RateLimitAlgorithm {
<<interface>>
+allowRequest(key: String): boolean
}
class FixedWindowAlgorithm {
-limit: int
-windowSizeMillis: long
-store: FixedWindowStore
+allowRequest(key: String): boolean
}
class SlidingWindowLogAlgorithm {
-limit: int
-windowSizeMillis: long
-store: SlidingWindowStore
+allowRequest(key: String): boolean
}
RateLimitAlgorithm <|.. FixedWindowAlgorithm : Implements
RateLimitAlgorithm <|.. SlidingWindowLogAlgorithm : Implements
%% ================= Storage Layer =================
class FixedWindowStore {
<<interface>>
+incrementAndGet(key: String, windowSize: long): long
}
class SlidingWindowStore {
<<interface>>
+addAndGetRecentWindowCount(key: String, now: long, windowStart: long): long
}
class RateLimitStore {
<<interface>>
}
FixedWindowStore <|-- RateLimitStore : Extends
SlidingWindowStore <|-- RateLimitStore : Extends
class InMemoryStore {
-fixedWindowCounters: Map
-slidingWindowLogs: Map
+incrementAndGet(key, windowSize)
+addAndGetRecentWindowCount(key, now, start)
}
RateLimitStore <|.. InMemoryStore : Implements
%% Algorithm to Store relationships (Interface Segregation)
FixedWindowAlgorithm o-- FixedWindowStore : Aggregation
SlidingWindowLogAlgorithm o-- SlidingWindowStore : Aggregation
%% ================= Key Extractors =================
class KeyExtractor {
<<interface>>
+extractKey(request: Request): String
}
class IpExtractor
class UserExtractor
class LocationExtractor
class EndpointExtractor
KeyExtractor <|.. IpExtractor : Implements
KeyExtractor <|.. UserExtractor : Implements
KeyExtractor <|.. LocationExtractor : Implements
KeyExtractor <|.. EndpointExtractor : Implements
%% ================= Database / Core App =================
class ApplicationRepository {
<<interface>>
+mockApi(): String
}
class MockDbCall
ApplicationRepository <|.. MockDbCall : Implements
%% ================= Creation (Builders & Factories) =================
class RateLimiterBuilder {
-algorithmType: String
-storeType: String
-extractorType: String
-limit: int
-windowSizeMillis: int
+withAlgorithm(type: String)
+withStore(type: String)
+withExtractor(type: String)
+build(): RateLimiter
}
class AlgorithmFactory {
<<static>>
+createAlgorithm() RateLimitAlgorithm
}
class StoreFactory {
<<static>>
+getStore() RateLimitStore
}
class ExtractorFactory {
<<static>>
+getExtractor() KeyExtractor
}
RateLimiterBuilder ..> AlgorithmFactory : Uses
RateLimiterBuilder ..> StoreFactory : Uses
RateLimiterBuilder ..> ExtractorFactory : Uses
RateLimiterBuilder ..> ApplicationRateLimiter : Creates
%% ================= Enums =================
class AlgorithmType { <<enumeration>> }
class StoreType { <<enumeration>> }
class ExtractorType { <<enumeration>> }
AlgorithmFactory ..> AlgorithmType : Uses
StoreFactory ..> StoreType : Uses
ExtractorFactory ..> ExtractorType : Uses
- Strategy Pattern: Algorithms (
FixedWindow,SlidingWindow) and Extractors (IpExtractor,UserExtractor) are interchangeable behavioral strategies without modifying the coreApplicationRateLimiter. - Builder Pattern:
RateLimiterBuilderabstracts the complex configuration logic and prevents the "Telescoping Constructor Anti-Pattern". - Factory Method Pattern:
AlgorithmFactory,StoreFactory, andExtractorFactoryhandle the instantiation logic, mapping String/Enum configurations to concrete classes. - Proxy / Decorator Pattern: The
ApplicationRateLimiteracts as a proxy, verifying the request quota before delegating the call to the underlyingApplicationRepository.
- Single Responsibility (SRP): Math is isolated in the
Algorithmclasses. Storage locking and thread safety are isolated in theInMemoryStore. - Open/Closed (OCP): Adding a
RedisStoreor aTokenBucketAlgorithmrequires creating a new class and adding a switch case in the factory—zero changes to core logic. - Liskov Substitution (LSP): Any implementation of
RateLimitAlgorithmcan seamlessly replace another without the Orchestrator knowing. - Interface Segregation (ISP):
FixedWindowAlgorithmonly depends onFixedWindowStore, not the fatRateLimitStoreinterface. - Dependency Inversion (DIP): The orchestrator depends entirely on abstractions (
RateLimitAlgorithm,KeyExtractor), not concrete implementations.
This project simulates a high-traffic environment with edge-case scenarios including exact quota exhaustion, rate limit resets via thread sleeping, and user isolation.
Ensure you have Java 17+ installed.
1. Compile the Source Code:
Navigate to the root directory (rate-limiter) and compile the classes, ensuring the source path is set correctly:
javac -sourcepath src src/Main.java2. Run the System: Execute the compiled classes from the root directory:
java -cp src Main