Tower Middleware Compatibility

Salvo provides compatibility support for the Tower ecosystem through the tower-compat feature. For detailed APIs, please refer to the documentation.

Core Concepts of Tower

Tower is a service abstraction library primarily built around two core traits:

Service Trait

pub trait Service<Request> {  
    type Response;  
    type Error;  
    type Future: Future<Output = Result<Self::Response, Self::Error>>;  

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>>;  
    fn call(&mut self, req: Request) -> Self::Future;  
}

The Service trait handles requests and returns responses, similar to Salvo's handler.

Layer Trait

pub trait Layer<S> {  
    type Service;  
    fn layer(&self, inner: S) -> Self::Service;  
}

The Layer trait wraps services to add additional functionality, analogous to Salvo's middleware.

Salvo Compatibility Support

Salvo offers two key traits to enable compatibility with the Tower ecosystem:

  • TowerLayerCompat: Converts Tower's Layer into Salvo's Handler, allowing it to be used as a Hoop (middleware).
  • TowerServiceCompat: Converts Tower's Service into Salvo's Handler.

Usage Example:

// Apply Tower's RateLimitLayer and convert it to a Salvo-compatible format using compat()  
let limit = RateLimitLayer::new(5, Duration::from_secs(30)).compat();  
let router = Router::new().hoop(limit).get(hello);

Example Code

main.rs
Cargo.toml
with-tower/src/main.rs
use salvo::prelude::*;
use tokio::time::Duration;
use tower::limit::RateLimitLayer;

#[handler]
async fn hello() -> &'static str {
    "Hello World"
}

#[tokio::main]
async fn main() {
    tracing_subscriber::fmt().init();

    let limit = RateLimitLayer::new(5, Duration::from_secs(30)).compat();
    let acceptor = TcpListener::new("0.0.0.0:5800").bind().await;
    let router = Router::new().hoop(limit).get(hello);
    Server::new(acceptor).serve(router).await;
}