In this blog, we’ll explore how to add rate limiting to a Spring Boot API using Bucket4j. Applying Rate limiting will help control the number of requests a client can make to your API within a certain period to protect server resources and ensure fair usage.
Introduction for Bucket4j
Bucket4j is a Java rate-limiting library that is used to implement various algorithms like token buckets and leaky buckets for rate limiting. It is highly efficient and easy to integrate with any Java-based application, including Spring Boot.
Let’s set up a Spring Boot Project
Create a spring boot app and add the below dependencies.
<!-- Bucket4j -->
<dependency> <groupId>com.github.vladimir-bukhtoyarov</groupId> <artifactId>bucket4j-core</artifactId> <version>3.1.0</version>
</dependency>
Creating a Rate Limiting Service
import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.Bucket4j;
import io.github.bucket4j.Refill; import java.time.Duration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; public class RateLimitingService { private final Map<String, Bucket> buckets = new ConcurrentHashMap<>(); public boolean allowRequest(String apiKey) { Bucket bucket = buckets.computeIfAbsent(apiKey, this::createNewBucket); return bucket.tryConsume(1); } private Bucket createNewBucket(String apiKey) { Bandwidth limit = Bandwidth.classic(10, Refill.intervally(10, Duration.ofMinutes(1))); return Bucket4j.builder().addLimit(limit).build(); }
}
**Note: If Refill.intervally is not available you can use Refill.smooth
In this RateLimitingService class:
We use a ConcurrentHashMap to store a bucket for each API key.
The allowRequest method checks if a request can be consumed from the bucket associated with the given API key.
The createNewBucket method creates a new bucket with a rate limit of 10 requests per minute.
Now let’s create a RateLimitingController class to integrate ratelimiting on API.
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
@RequestMapping("/api/rate-limiting")
public class RateLimitingController { private final RateLimitingService rateLimitingService; public RateLimitingController(RateLimitingService rateLimitingService) { this.rateLimitingService = rateLimitingService; } @GetMapping("/resource") public String getResource() { String apiKey = "test-api-key"; // Retrieve API key from request headers or JWT token if (rateLimitingService.allowRequest(apiKey)) { return "Resource api accessed successfully"; } else { return "Rate limit exceeded. Please Try again later."; } }
}
In this RateLimitingController class:
We inject the RateLimitingService into the controller.
The getResource method checks if the request can be allowed based on the rate limit associated with the API key.
Conclusion
In this tutorial, it’s shown how to use Bucket4j to build rate restrictions in a Spring Boot API. You can protect your APIs against misuse and guarantee equitable client usage by managing the volume of incoming requests. Token buckets and other algorithm-based rate constraints can be effectively and adaptably implemented using Bucket4j. You are welcome to alter the rate-limiting parameters to suit the needs of your particular application.
For more advanced scenarios, consider integrating Bucket4j with caching mechanisms like Redis for distributed rate limiting across multiple server instances.
References
https://bucket4j.com/
https://github.com/bucket4j/bucket4j
https://github.com/bucket4j/bucket4j