Travis (.org) Crates.io Crates.io

actix-ratelimit

Rate limiting middleware framework for actix-web

This crate provides an asynchronous and concurrent rate limiting middleware based on actor model which can be wraped around an Actix application. Middleware contains a store which is used to identify client request.

Check out the documentation here.

Comments, suggesstions and critiques are welcome!

Usage

Add this to your Cargo.toml: toml [dependencies] actix-ratelimit = "0.3.1"

Version 0.3.* supports actix-web v3. If you're using actix-web v2, consider using version 0.2.*.

Minimal example:

```rust use actixweb::{web, App, HttpRequest, HttpServer, Responder}; use actixratelimit::{RateLimiter, MemoryStore, MemoryStoreActor}; use std::time::Duration;

async fn greet(req: HttpRequest) -> impl Responder{ let name = req.matchinfo().get("name").unwrapor("World!"); format!("Hello {}!", &name) }

[actix_web::main]

async fn main() -> std::io::Result<()> { // Initialize store let store = MemoryStore::new(); HttpServer::new(move ||{ App::new() // Register the middleware // which allows for a maximum of // 100 requests per minute per client // based on IP address .wrap( RateLimiter::new( MemoryStoreActor::from(store.clone()).start()) .withinterval(Duration::fromsecs(60)) .withmaxrequests(100) ) .route("/", web::get().to(greet)) .route("/{name}", web::get().to(greet)) }) .bind("127.0.0.1:8000")? .run() .await } Sending a request returns a response with the ratelimiting headers: shell $ curl -i "http://localhost:8000/"

HTTP/1.1 200 OK content-length: 13 content-type: text/plain; charset=utf-8 x-ratelimit-remaining: 99 x-ratelimit-reset: 52 x-ratelimit-limit: 100 date: Tue, 04 Feb 2020 21:53:27 GMT

Hello World! ``` Exceeding the limit returns HTTP 429 Error code.

Stores

A store is a data structure, database connection or anything which can be used to store ratelimit data associated with a client. A store actor which acts on this store is responsible for performiing all sorts of operations(SET, GET, DEL, etc). It is Important to note that there are multiple store actors acting on a single store.

List of features

Implementing your own store

To implement your own store, you have to implement an Actor which can handle ActorMessage type and return ActorResponse type. Check the module level documentation for more details and a basic example.

Note to developers

async fn main() -> std::io::Result<()> { // Initialize store let store = MemoryStore::new(); HttpServer::new(move ||{ App::new() .wrap( RateLimiter::new( MemoryStoreActor::from(store.clone()).start()) .withinterval(Duration::fromsecs(60)) .withmaxrequests(100) .withidentifier(|req| { let key = req.headers().get("x-api-key").unwrap(); let key = key.tostr().unwrap(); Ok(key.to_string()) }) ) .route("/", web::get().to(greet)) .route("/{name}", web::get().to(greet)) }) .bind("127.0.0.1:8000")? .run() .await } ```

async fn main() -> std::io::Result<()> { HttpServer::new(move ||{ App::new() .wrap( RateLimiter::new( MemoryStoreActor::from(MemoryStore::new()).start()) .withinterval(Duration::fromsecs(60)) .withmaxrequests(100) ) .route("/", web::get().to(greet)) .route("/{name}", web::get().to(greet)) }) .bind("127.0.0.1:8000")? .run() .await } ```

Status

This project has not reached v1.0, so some instability and breaking changes are to be expected till then.

You can use the issue tracker in case you encounter any problems.

LICENSE

This project is licensed under MIT license.

License: MIT