axum_governor/
lib.rs

1/* src/lib.rs */
2
3//! # Axum Governor
4//!
5//! A rate-limiting middleware for Axum, powered by `lazy-limit` and `real`.
6//!
7//! This crate provides a simple and configurable Tower layer to enforce rate limits
8//! on your Axum application based on the client's real IP address.
9//!
10//! ## Features
11//!
12//! - **IP-Based Limiting**: Uses the `real` crate to accurately identify the client's IP address.
13//! - **Flexible Rules**: Leverages `lazy-limit` to support global and route-specific rate limits.
14//! - **Two Modes**: Supports both standard mode (respecting global and route rules) and override mode (ignoring global rules).
15//! - **Easy Integration**: Implemented as a standard Tower `Layer`.
16//!
17//! ## Quick Start
18//!
19//! 1.  **Add Dependencies**:
20//!
21//!     ```toml
22//!     [dependencies]
23//!     axum-governor = "0.1.0"
24//!     lazy-limit = "1"
25//!     tokio = { version = "1", features = ["full"] }
26//!     real = { version = "0.1", features = ["axum"] }
27//!     ```
28//!
29//! 2.  **Initialize the Rate Limiter**:
30//!
31//!     Before starting your application, initialize `lazy-limit` with your desired rules.
32//!
33//!     ```rust
34//!     use lazy_limit::{init_rate_limiter, Duration, RuleConfig};
35//!
36//!     #[tokio::main]
37//!     async fn main() {
38//!         init_rate_limiter!(
39//!             default: RuleConfig::new(Duration::seconds(1), 5), // 5 req/s globally
40//!             routes: [
41//!                 ("/api/special", RuleConfig::new(Duration::seconds(1), 10)),
42//!             ]
43//!         ).await;
44//!
45//!         // ... your Axum app setup
46//!     }
47//!     ```
48//!
49//! 3.  **Add Layers to Your Router**:
50//!
51//!     The `GovernorLayer` requires the `RealIpLayer` to be present. Always add `RealIpLayer` first.
52//!
53//!     ```rust
54//!     # use axum::{Router, routing::get};
55//!     # use axum_governor::GovernorLayer;
56//!     # use real::RealIpLayer;
57//!     # use std::net::SocketAddr;
58//!     # async fn handler() -> &'static str { "Hello!" }
59//!     # async {
60//!     let app = Router::new()
61//!         .route("/", get(handler))
62//!         .layer(
63//!             tower::ServiceBuilder::new()
64//!                 .layer(RealIpLayer::default()) // Extracts the real IP
65//!                 .layer(GovernorLayer::default())   // Applies rate limiting
66//!         );
67//!
68//!     let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
69//!     let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
70//!     axum::serve(listener, app.into_make_service_with_connect_info::<SocketAddr>())
71//!         .await
72//!         .unwrap();
73//!     # };
74//!     ```
75
76use axum::http::Method;
77use lazy_limit::HttpMethod;
78
79// Public exports
80pub use config::GovernorConfig;
81pub use layer::GovernorLayer;
82pub use middleware::GovernorMiddleware;
83
84// Module declarations
85mod config;
86mod layer;
87mod middleware;
88
89pub fn map_method(m: Method) -> HttpMethod {
90    match m {
91        Method::GET => HttpMethod::GET,
92        Method::POST => HttpMethod::POST,
93        Method::PUT => HttpMethod::PUT,
94        Method::DELETE => HttpMethod::DELETE,
95        Method::PATCH => HttpMethod::PATCH,
96        Method::HEAD => HttpMethod::HEAD,
97        Method::OPTIONS => HttpMethod::OPTIONS,
98        Method::CONNECT => HttpMethod::CONNECT,
99        Method::TRACE => HttpMethod::TRACE,
100        _ => HttpMethod::OTHER,
101    }
102}