@RateLimit annotation provides a declarative way to add rate limiting to your Spring Boot application endpoints.
import io.github.v4runsharma.ratelimiter.annotation.RateLimit;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
@RestController
public class ApiController {
@RateLimit(limit = 10, duration = 1, timeUnit = TimeUnit.MINUTES)
@GetMapping("/api/data")
public String getData() {
return "Hello World";
}
}
@RateLimit(limit = 100, duration = 1, timeUnit = TimeUnit.HOURS)
@RestController
public class ApiController {
@GetMapping("/api/users")
public List<User> getUsers() {
return userService.findAll();
}
@GetMapping("/api/posts")
public List<Post> getPosts() {
return postService.findAll();
}
}
// Global rate limit (shared across all users)
@RateLimit(limit = 100, duration = 1, scope = "global", timeUnit = TimeUnit.MINUTES)
@GetMapping("/api/public")
public String getPublicData() {
return "Public data";
}
// Per-user rate limit
@RateLimit(limit = 10, duration = 1, scope = "user", timeUnit = TimeUnit.MINUTES)
@GetMapping("/api/profile")
public User getProfile() {
return userService.getCurrentUser();
}
// Per-IP rate limit
@RateLimit(limit = 5, duration = 1, scope = "ip", timeUnit = TimeUnit.MINUTES)
@GetMapping("/api/login")
public String login() {
return "Login successful";
}
@RateLimit(limit = 5, duration = 1, key = "search", timeUnit = TimeUnit.SECONDS)
@GetMapping("/api/search")
public List<Result> search(@RequestParam String query) {
return searchService.search(query);
}
@RateLimit(limit = 10, duration = 1, key = "export", timeUnit = TimeUnit.MINUTES)
@GetMapping("/api/export")
public byte[] export() {
return exportService.generateReport();
}
@RateLimit(
name = "api-search",
limit = 20,
duration = 1,
timeUnit = TimeUnit.MINUTES
)
@GetMapping("/api/search")
public List<Result> search(@RequestParam String query) {
return searchService.search(query);
}
@RateLimit(
limit = 10,
duration = 1,
enabled = false,
timeUnit = TimeUnit.MINUTES
)
@GetMapping("/api/debug")
public String debug() {
return "Debug info";
}
Annotation reference
The@RateLimit annotation supports the following parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
limit | int | Yes | - | Maximum number of requests allowed within the window |
duration | long | Yes | - | Window size in the specified time unit |
timeUnit | TimeUnit | No | SECONDS | Time unit for the duration (SECONDS, MINUTES, HOURS, etc.) |
scope | String | No | "" | Scope hint for the rate limit (e.g., “user”, “ip”, “global”) |
key | String | No | "" | Static key suffix to differentiate limits |
name | String | No | "" | Logical name for metrics and monitoring |
enabled | boolean | No | true | Whether rate limiting is enabled |
keyResolver | Class | No | RateLimitKeyResolver.class | Custom key resolver implementation |
How it works
When a method annotated with@RateLimit is called:
- The AOP interceptor captures the invocation (see
RateLimitAspect.java:24-44) - A key is resolved based on the scope and configuration
- The rate limiter checks if the request exceeds the limit
- If allowed, the method proceeds normally
- If blocked, a
RateLimitExceededExceptionis thrown, which returns HTTP 429