How to use tower crate in Rust service abstractions

Use the tower crate by defining a Service for core logic and wrapping it with Layers via ServiceBuilder to add middleware like tracing or timeouts.

Use the tower crate by defining a Service for your core logic, wrapping it with Layers for cross-cutting concerns, and stacking them with ServiceBuilder.

use tower::{Service, ServiceBuilder, ServiceExt, layer::LayerFn};
use tower_http::trace::TraceLayer;
use http::{Request, Response, StatusCode};
use std::convert::Infallible;

// 1. Define your core service
struct MyService;

impl Service<Request<String>> for MyService {
    type Response = Response<String>;
    type Error = Infallible;
    type Future = std::future::Ready<Result<Self::Response, Self::Error>>;

    fn poll_ready(
        &mut self,
        _cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Result<(), Self::Error>> {
        std::task::Poll::Ready(Ok(()))
    }

    fn call(&mut self, req: Request<String>) -> Self::Future {
        let body = format!("Received: {}", req.into_body());
        std::future::ready(Ok(Response::new(body)))
    }
}

// 2. Build the stack
let mut service = ServiceBuilder::new()
    .layer(TraceLayer::new_for_http()) // Middleware
    .service(MyService);

// 3. Call the service
let req = Request::new("Hello".to_string());
let response = service.ready().await?.call(req);