Understanding key resolvers
TheRateLimitKeyResolver interface (from key/RateLimitKeyResolver.java:11-21) is responsible for generating a unique key that identifies which bucket a request should be counted against:
Default behavior
TheDefaultRateLimitKeyResolver (from key/DefaultRateLimitKeyResolver.java:11-32) creates keys from scope and method metadata:
global:com.example.ApiController#getDatauser:search(whenkey = "search"is specified)
package com.example.ratelimit;
import io.github.v4runsharma.ratelimiter.core.RateLimitContext;
import io.github.v4runsharma.ratelimiter.key.RateLimitKeyResolver;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
@Component
public class UserIdKeyResolver implements RateLimitKeyResolver {
@Override
public String resolveKey(RateLimitContext context) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth == null || !auth.isAuthenticated()) {
return "anonymous";
}
String userId = auth.getName();
String methodName = context.getMethod().getName();
return "user:" + userId + ":" + methodName;
}
}
import com.example.ratelimit.UserIdKeyResolver;
import io.github.v4runsharma.ratelimiter.annotation.RateLimit;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ApiController {
@RateLimit(
limit = 10,
duration = 1,
keyResolver = UserIdKeyResolver.class
)
@GetMapping("/api/data")
public String getData() {
return "Data";
}
}
The
RateLimitContext interface (from core/RateLimitContext.java:15-46) provides rich information about the invocation:public interface RateLimitContext {
RateLimit getAnnotation(); // The @RateLimit annotation
Class<?> getTargetClass(); // The controller class
Method getMethod(); // The method being called
Object[] getArguments(); // Method arguments
Object getTarget(); // The target instance
}
Example: API key resolver
Limit requests per API key extracted from a header:Example: Tenant-based resolver
Group rate limits by tenant ID:Example: Parameter-based resolver
Extract keys from method parameters:Best practices
Return stable, predictable keys
Keys should be deterministic - the same caller should always get the same key:Handle missing context gracefully
Always provide a fallback when context is unavailable:Use meaningful prefixes
Prefix keys with their type for clarity and to avoid collisions:Consider key cardinality
Be mindful of how many unique keys you generate:Register as default resolver
To use your resolver as the default for all annotations:@RateLimit annotations without an explicit keyResolver will use your custom resolver.