# actix-web-ratelimit
A simple and highly customizable rate limiting middleware for actix-web 4.
[](https://crates.io/crates/actix-web-ratelimit)
[](https://docs.rs/actix-web-ratelimit)
[](https://opensource.org/licenses/MIT)
[](https://github.com/bigyao25/actix-web-ratelimit/actions/workflows/CI.yml)
[中文文档](README-cn.md)
## Features
- **actix-web 4 Compatible**: Built specifically for actix-web 4
- **Simple & Easy to Use**: Minimal configuration required
- **Expandable Store**: easy to create your own store, In-Memory store and Redis store have been provided
- **High Performance**: Efficient sliding window algorithm
- **Customizable**: Custom client identification and rate limit exceeded handlers
- **Thread Safe**: Concurrent request handling with DashMap
## Quick Start
Add this to your `Cargo.toml`:
```toml
[dependencies]
actix-web-ratelimit = "0.1"
# Or, for Redis support
actix-web-ratelimit = { version = "0.1", features = ["redis"] }
```
## Usage
### Basic Usage with In-Memory Store
```rust
// Configure rate limiting: allow 3 requests per 10-second window
let config = RateLimitConfig::default().max_requests(3).window_secs(10);
// Create in-memory store for tracking request timestamps
let store = Arc::new(MemoryStore::new());
HttpServer::new(move || {
App::new()
// create and register the rate limit middleware
.wrap(RateLimit::new(config.clone(), store.clone()))
.route("/", web::get().to(index))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
```
### Advanced Configuration
```rust
let store = Arc::new(MemoryStore::new());
let config = RateLimitConfig::default()
.max_requests(3)
.window_secs(10)
// Extract client identifier from req. It is IP (realip_remote_addr) by default.
.id(|req| {
req.headers()
.get("X-Client-Id")
.and_then(|h| h.to_str().ok())
.unwrap_or("anonymous")
.to_string()
})
// Custom handler for rate limit exceeded. It returns a 429 response by default.
.exceeded(|id, config, _req| {
HttpResponse::TooManyRequests().body(format!(
"429 caused: client-id: {}, limit: {}req/{:?}",
id, config.max_requests, config.window_secs
))
});
HttpServer::new(move || {
App::new()
.wrap(RateLimit::new(config.clone(), store.clone()))
.route("/", web::get().to(index))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
```
### Redis Store
first set feature `redis` enable:
```toml
actix-web-ratelimit = { version = "0.1", features = [ "redis" ] }
```
then you can use it:
```rust
let store = Arc::new(
RedisStore::new("redis://127.0.0.1/0")
.expect("Failed to connect to Redis")
// Custom prefix for Redis keys
.with_prefix("myapp:ratelimit:"),
);
let config = RateLimitConfig::default().max_requests(3).window_secs(10);
HttpServer::new(move || {
App::new()
.wrap(RateLimit::new(config.clone(), store.clone()))
.route("/", web::get().to(index))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
```
## Configuration Options
### RateLimitConfig
| `max_requests(usize)` | Maximum requests per window | 10 |
| `window_secs(u64)` | Time window in seconds | 100 |
| `id(fn)` | Client identification function | IP address |
| `exceeded(fn)` | Rate limit exceeded handler | 429 response |
### Storage Backends
#### MemoryStore
- **Pros**: Fast, no external dependencies
- **Cons**: Not distributed, data lost on restart
- **Use case**: Single instance applications
#### RedisStore (requires `redis` feature)
- **Pros**: Distributed, persistent, scalable
- **Cons**: Requires Redis server
- **Use case**: Multi-instance applications
## Algorithm
This middleware uses a **sliding window** algorithm:
1. Extract client identifier from request
2. Retrieve stored request timestamps for the client
3. Remove expired timestamps outside the time window
4. Check if remaining request count exceeds the limit
5. If not exceeded, record new timestamp and allow request
6. If exceeded, call the rate limit handler
## Examples
Run the example:
```bash
cargo run --example simple
```
Then test the rate limiting:
```bash
# This should work
curl http://localhost:8080/
# Exceed rate limit by making many requests
for i in {1..5}; do echo "$(curl -s http://localhost:8080)\r"; done
```
## [features]
- `redis`: Enables Redis storage backend support
## License
This project is licensed under the [MIT License](LICENSE).