The Goal
Decouple the sender of a request from its receivers by giving multiple objects a chance to handle the request.
Instead of writing a massive if-else block to validate an incoming API request, you create a chain of standalone filters. If a filter passes, it hands the request to the next link. If it fails, the chain breaks immediately.
- The Handler Interface
public abstract class ApiFilter {
private ApiFilter nextFilter;
public void setNext(ApiFilter nextFilter) {
this.nextFilter = nextFilter;
}
public void filter(String request) {
if (handle(request) && nextFilter != null) {
// Hand off to the next link in the chain
nextFilter.filter(request);
}
}
// Subclasses implement their specific logic here
protected abstract boolean handle(String request);
}
- Concrete Handlers
public class RateLimitFilter extends ApiFilter {
protected boolean handle(String request) {
System.out.println("Rate limit check passed.");
return true;
}
}
public class JwtAuthFilter extends ApiFilter {
protected boolean handle(String request) {
if (request.contains("Bearer")) {
System.out.println("JWT Validated.");
return true;
}
System.out.println("401 Unauthorized.");
return false; // Breaks the chain!
}
}
- Usage: Wiring the chain
ApiFilter rateLimiter = new RateLimitFilter();
ApiFilter auth = new JwtAuthFilter();
rateLimiter.setNext(auth); // Link them together
- The client just hits the first link
rateLimiter.filter("GET /api/v1/users Headers: Bearer abc123_");