A Tower service and layer that provides a rate-limiting backed by governor. Based heavily on the work done for actix-governor. Works with Axum, Hyper, Tower, Tonic, and anything else based on Tower!
# Features:
Robust yet flexible API
Each governor middleware has a configuration that stores a quota. The quota specifies how many requests can be sent from an IP address before the middleware starts blocking further requests.
For example if the quota allowed ten requests a client could send a burst of ten requests in short time before the middleware starts blocking.
Once at least one element of the quota was used the elements of the quota will be replenished after a specified period.
For example if this period was 2 seconds and the quota was empty it would take 2 seconds to replenish one element of the quota. This means you could send one request every two seconds on average.
If there was a quota that allowed ten requests with the same period a client could again send a burst of ten requests and then had to wait two seconds before sending further requests or 20 seconds before the full quota would be replenished and he could send another burst.
```rust,norun use axum::{routing::get, Router, errorhandling::HandleErrorLayer, BoxError}; use towergovernor::{ governor::{GovernorConfigBuilder}, errors::{displayerror}, GovernorLayer, }; use tower::{ServiceBuilder}; use std::net::SocketAddr;
async fn hello() -> &'static str { "Hello world" }
async fn main() {
// Configure tracing if desired
// construct a subscriber that prints formatted traces to stdout
let subscriber = tracing_subscriber::FmtSubscriber::new();
// use that subscriber to process traces emitted after this point
tracing::subscriber::set_global_default(subscriber).unwrap();
// Allow bursts with up to five requests per IP address
// and replenishes one element every two seconds
let governor_conf = GovernorConfigBuilder::default()
.per_second(2)
.burst_size(5)
.finish()
.unwrap();
// build our application with a route
let app = Router::new()
// `GET /` goes to `root`
.route("/", get(hello))
.layer(
ServiceBuilder::new()
// this middleware goes above `GovernorLayer` because it will receive
// errors returned by `GovernorLayer`
.layer(HandleErrorLayer::new(|e: BoxError| async move {
display_error(e)
}))
.layer(GovernorLayer {
config: &governor_conf,
})
);
// run our app with hyper
// `axum::Server` is a re-export of `hyper::Server`
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
tracing::debug!("listening on {}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service_with_connect_info::<SocketAddr>())
.await
.unwrap();
} ```
# Configuration presets
Instead of using the configuration builder you can use predefined presets.
GovernorConfig::default()
: The default configuration which is suitable for most services.
Allows bursts with up to eight requests and replenishes one element after 500ms, based on peer IP.
GovernorConfig::secure()
: A default configuration for security related services.
Allows bursts with up to two requests and replenishes one element after four seconds, based on peer IP.
For example the secure configuration can be used as a short version of this code:
```rust use tower_governor::governor::GovernorConfigBuilder;
let config = GovernorConfigBuilder::default() .persecond(4) .burstsize(2) .finish() .unwrap(); ```
By default, rate limiting is done using the peer IP address (i.e. the IP address of the HTTP client that requested your app: either your user or a reverse proxy, depending on your deployment setup). You can configure a different behavior which:
allows you to setup multiple instances of this middleware based on different keys (for example, if you want to apply rate limiting with different rates on IP and API keys at the same time)
This is achieved by defining a [KeyExtractor] and giving it to a [Governor] instance. Three ready-to-use key extractors are provided:
[GlobalKeyExtractor]: uses the same key for all incoming requests
Check out the [customkeybearer] example for more information.
By default, x-ratelimit-after
is enabled but if you want to enable x-ratelimit-limit
, x-ratelimit-whitelisted
and x-ratelimit-remaining
use [use_headers
] method
This crate surfaces a GovernorError with suggested headers, and includes a [display_error
]: crate::errors::display_error() function that will turn those errors into a Response. Feel free to provide your own error handler that takes in a BoxError and returns a Response
. Tower Layers require that all Errors be handled, or it will fail to compile.
Do not construct the same configuration multiple times, unless explicitly wanted!
This will create an independent rate limiter for each configuration! Instead pass the same configuration reference into [Governor::new()
], like it is described in the example.
Be careful to create your server with .into_make_service_with_connection_info::<SocketAddr>
instead of .into_make_service()
if you are using the default PeerIpKeyExtractor. Otherwise there will be no peer ip address for Tower to find!