#tower-service #async-trait #layer #traits #request #concise #implemented

service-layer-rs

A simple alternative to the tower service layer, implemented using async trait, making the code more concise and easier to use

8 unstable releases (3 breaking)

0.5.1 Oct 5, 2024
0.5.0 Oct 5, 2024
0.3.2 Oct 4, 2024
0.2.3 Oct 4, 2024
0.1.3 Sep 30, 2024

#777 in Rust patterns

Download history 879/week @ 2024-09-28 214/week @ 2024-10-05 81/week @ 2024-10-12

1,174 downloads per month

MIT/Apache

14KB
291 lines

service-layer-rs

A simple alternative to the tower service layer, implemented using async trait, making the code more concise and easier to use.

Example

use service_layer_rs::util::FnService;
use service_layer_rs::{Layer, Service, ServiceBuilder};
use std::convert::Infallible;

pub struct LogService<S> {
    inner: S,
    name: String,
}

impl<S, Request> Service<Request> for LogService<S>
where
    S: Service<Request>,
    Request: Send + 'static,
{
    type Response = S::Response;
    type Error = S::Error;

    async fn call(
        &self,
        request: Request,
    ) -> Result<Self::Response, Self::Error> {
        println!("LogService<{}> start", self.name);
        let res = self.inner.call(request).await;
        println!("LogService<{}> end", self.name);
        res
    }
}

pub struct LogLayer(pub String);

impl<S> Layer<S> for LogLayer
where
    S: Send + Sync + 'static
{
    type Service = LogService<S>;

    fn layer(self, inner: S) -> Self::Service {
        LogService { inner, name: self.0 }
    }
}

#[tokio::main]
async fn main() {
    let svc = FnService::new(|request: String| async move {
        println!("handle: {}", request);
        Ok::<_, Infallible>(request)
    });

    let svc = ServiceBuilder::service(svc)
        .layer(LogLayer("Test".to_string()))
        .build();

    let ss = svc.boxed();
    let res: Result<String, Infallible> = ss.call("hello".to_owned()).await;
    println!("{:?}", res);
}

Dynamic Dispatch

let svc = FnService::new(|request: String| async move {
    println!("handle: {}", request);
    Ok::<_, Infallible>(request)
});

// Box this service to allow for dynamic dispatch.
let svc = ServiceBuilder::new(svc)
    .layer(LogLayer("Test".to_string()))
    .build()
    .boxed();

let res: Result<String, Infallible> = svc.call("hello".to_owned()).await;
println!("{:?}", res);

No runtime deps