Overview
The RateLimitKeyResolver interface resolves a stable rate limit key for an invocation. The key identifies which bucket or counter to charge against, enabling different limiting strategies like per-user, per-IP, or per-endpoint.
Package: io.github.v4runsharma.ratelimiter.key
Source: RateLimitKeyResolver.java:11
Purpose
The returned key is what the RateLimiter charges against. Different resolvers enable:
- Per-user rate limiting
- Per-IP rate limiting
- Per-API-key rate limiting
- Per-endpoint rate limiting
- Custom composite keys
Methods
resolveKey
String resolveKey(RateLimitContext context)
Computes a key identifying the caller or resource bucket.
Guidelines:
- Return a non-empty, stable string (same caller → same key)
- Prefer predictable formats (e.g., “user:123”, “ip:203.0.113.10”)
- Consider including scope prefix for clarity
The invocation context containing the annotation, method, target class, and arguments.
A stable, non-empty key string identifying the rate limit bucket.
Usage examples
Per-user key resolver
import io.github.v4runsharma.ratelimiter.key.RateLimitKeyResolver;
import io.github.v4runsharma.ratelimiter.core.RateLimitContext;
import org.springframework.security.core.context.SecurityContextHolder;
public class UserKeyResolver implements RateLimitKeyResolver {
@Override
public String resolveKey(RateLimitContext context) {
// Get user from security context
String username = SecurityContextHolder.getContext()
.getAuthentication()
.getName();
// Return user-scoped key
return "user:" + username;
}
}
Per-IP key resolver
import io.github.v4runsharma.ratelimiter.key.RateLimitKeyResolver;
import io.github.v4runsharma.ratelimiter.core.RateLimitContext;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
public class IpKeyResolver implements RateLimitKeyResolver {
@Override
public String resolveKey(RateLimitContext context) {
ServletRequestAttributes attrs =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attrs != null) {
HttpServletRequest request = attrs.getRequest();
String ip = getClientIp(request);
return "ip:" + ip;
}
return "ip:unknown";
}
private String getClientIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.isEmpty()) {
ip = request.getRemoteAddr();
} else {
// Take first IP in X-Forwarded-For chain
ip = ip.split(",")[0].trim();
}
return ip;
}
}
Parameter-based key resolver
import io.github.v4runsharma.ratelimiter.key.RateLimitKeyResolver;
import io.github.v4runsharma.ratelimiter.core.RateLimitContext;
import java.lang.reflect.Parameter;
public class ParameterKeyResolver implements RateLimitKeyResolver {
@Override
public String resolveKey(RateLimitContext context) {
// Find parameter annotated with @RateLimitKey
Parameter[] parameters = context.getMethod().getParameters();
Object[] arguments = context.getArguments();
for (int i = 0; i < parameters.length; i++) {
if (parameters[i].isAnnotationPresent(RateLimitKey.class)) {
Object value = arguments[i];
return "param:" + value.toString();
}
}
// Fallback to method-based key
return "method:" + context.getMethod().getName();
}
}
API key resolver
import io.github.v4runsharma.ratelimiter.key.RateLimitKeyResolver;
import io.github.v4runsharma.ratelimiter.core.RateLimitContext;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
public class ApiKeyResolver implements RateLimitKeyResolver {
@Override
public String resolveKey(RateLimitContext context) {
ServletRequestAttributes attrs =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attrs != null) {
HttpServletRequest request = attrs.getRequest();
String apiKey = request.getHeader("X-API-Key");
if (apiKey != null && !apiKey.isEmpty()) {
return "apikey:" + apiKey;
}
}
return "apikey:anonymous";
}
}
Composite key resolver
import io.github.v4runsharma.ratelimiter.key.RateLimitKeyResolver;
import io.github.v4runsharma.ratelimiter.core.RateLimitContext;
public class CompositeKeyResolver implements RateLimitKeyResolver {
@Override
public String resolveKey(RateLimitContext context) {
String scope = context.getAnnotation().scope();
String methodKey = context.getTargetClass().getSimpleName()
+ "." + context.getMethod().getName();
// Combine scope and method into composite key
return scope + ":" + methodKey;
}
}
Configuring custom resolver
You can specify a custom resolver in the @RateLimit annotation:
import io.github.v4runsharma.ratelimiter.annotation.RateLimit;
public class UserController {
@RateLimit(
limit = 100,
duration = 1,
keyResolver = UserKeyResolver.class
)
public void getUserProfile(String userId) {
// Method implementation
}
}
Or configure it globally as a Spring bean:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RateLimitConfig {
@Bean
public RateLimitKeyResolver rateLimitKeyResolver() {
return new UserKeyResolver();
}
}