Rate limiting
Throttle is a fixed-window limiter: at most max hits per key in each window. As middleware the key is the client address, and a client over the limit gets 429 with Retry-After.
On routes#
use std::time::Duration;
use rustclamp::web::{Router, Throttle, json, redirect, throttle};
Router::new()
.group(|api| {
api.middleware(throttle(60, Duration::from_secs(60))) // 60 per minute per client
.get("/api/health", |_| json(r#"{"status":"ok"}"#))
})
.group(|login| {
login.middleware(Throttle::per_minute(5).trust_forwarded(true).middleware())
.post("/login", |_| redirect("/"))
})
The web template reads API_PER_MINUTE from .env and throttles /api/* with it.
Behind a proxy#
Behind nginx every request arrives from 127.0.0.1, so all visitors would share one limit. trust_forwarded(true) keys by the last X-Forwarded-For address, the one your proxy added. Turn it on only behind exactly one proxy that sets that header: without one, clients could choose their own key. The template maps it to TRUST_PROXY.
Outside HTTP#
The same limiter works anywhere: a console command, a job, a login attempt counter.
let limit = Throttle::new(3, Duration::from_secs(3600)); // 3 per hour per key
match limit.hit(user) {
Ok(()) => send_reset_email(user),
Err(wait) => println!("try again in {}s", wait.as_secs()),
}
Counts live in memory in one process, so they reset when the server restarts.