I would like to restrict frequent requests to my Spring Boot controller for example based on an incoming parameter a country, allow only n requests per m seconds from a particular country.
I have some solution however would like to ask whether there is a better (proper, more elegant) approach.
Controller:
@RestController
public class UslugiController {
@Autowired
private CheckService checkService;
@GetMapping("/apply/{country}")
public ResponseEntity<?> apply(@PathVariable String country){
if (!checkService.allowRequestByFrequency(country)){
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body("{\"message\":\"Too frequent requests\"}");
}
return ResponseEntity
.status(HttpStatus.OK)
.body("{\"message\":\"OK\"}");
}
}
Service:
@Service
public class CheckService {
private Map<String, CircularFifoQueue<LocalTime>> requests = new HashMap<>();
@Value("${max.time.period.sec}")
private int maxAllowedPeriodSeconds;
@Value("${max.number.requests.in.period}")
public int numberRequestsInPeriod;
@PostConstruct
private void post() {
requests.put("EN", new CircularFifoQueue<LocalTime>(numberRequestsInPeriod));
requests.put("RU", new CircularFifoQueue<LocalTime>(numberRequestsInPeriod));
}
// check if a number of requests for particular country is not more then n per m seconds
public boolean allowRequestByFrequency(String country) {
CircularFifoQueue<LocalTime> requestsTimes = requests.get(country);
requestsTimes.add(LocalTime.now());
//wait until queue is full
if (!requestsTimes.isAtFullCapacity()){
return true;
}
LocalTime firstReq = requestsTimes.get(0);
LocalTime lastReq = requestsTimes.get(requestsTimes.maxSize()-1);
long periodSeconds = Duration.between(firstReq, lastReq).getSeconds();
return periodSeconds > maxAllowedPeriodSeconds;
}
}