How To Create A Rate Limiter Module In Spring Boot

Rate limiter module in Spring Boot using the Spring Boot Starter Web and Spring Boot Starter Data Redis:

Step 1: Add Dependencies Add the necessary dependencies to your pom.xml file:

				
					<dependencies>
    <!-- Other dependencies -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
</dependencies>
				
			

Step 2: Configure Redis Configure your Redis connection details in the application.properties file:

				
					spring.redis.host=localhost
spring.redis.port=6379
				
			

Step 3: Create a Rate Limiter Interceptor Create an interceptor class called RateLimiterInterceptor to intercept incoming requests and apply rate limiting rules:

				
					import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;

@Component
public class RateLimiterInterceptor implements HandlerInterceptor {

    private final RedisTemplate<String, String> redisTemplate;

    @Autowired
    public RateLimiterInterceptor(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String clientIP = request.getRemoteAddr();
        String key = "rate_limit:" + clientIP;
        long maxRequestsPerMinute = 60;
        long windowDurationMinutes = 1;

        Long requests = redisTemplate.opsForValue().increment(key, 1);
        if (requests == null || requests == 1) {
            redisTemplate.expire(key, windowDurationMinutes, TimeUnit.MINUTES);
        }

        if (requests != null && requests > maxRequestsPerMinute) {
            response.setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);
            response.getWriter().write("Too Many Requests");
            return false;
        }

        return true;
    }
}
				
			

In this example, the RateLimiterInterceptor class implements the HandlerInterceptor interface. It uses a Redis template to store and increment the request count for each client IP address. The preHandle method intercepts the request, increments the request count, and checks if it exceeds the maximum number of requests per minute. If the limit is exceeded, a 429 Too Many Requests response is returned.

Step 4: Register the Rate Limiter Interceptor Register the RateLimiterInterceptor as an interceptor in your application configuration:

				
					import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    private final RateLimiterInterceptor rateLimiterInterceptor;

    @Autowired
    public WebConfig(RateLimiterInterceptor rateLimiterInterceptor) {
        this.rateLimiterInterceptor = rateLimiterInterceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(rateLimiterInterceptor);
    }
}
				
			

In this example, the RateLimiterInterceptor is added to the InterceptorRegistry to apply rate limiting to all incoming requests.

Please note that this is a basic example of a rate limiter module in Spring Boot using a Redis-based implementation. You can customize the rate limiting rules (maxRequestsPerMinute and windowDurationMinutes) and apply the interceptor to specific routes or route groups as per your requirements. Additionally, you may need to handle exceptions, configure Redis connection pooling, and adjust the Redis key format based on your application’s needs.