How to Write Tower-Style Middleware in Rust
Tower-style middleware in Rust is implemented by creating a struct that wraps a service and implements the Service trait to intercept requests before and after they reach the inner service.
use tower::{Service, ServiceExt};
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
struct MyMiddleware<S> {
inner: S,
}
// Define a concrete future type to wrap the inner service's future
struct MyFuture<F> {
inner: F,
}
impl<F> Future for MyFuture<F>
where
F: Future,
{
type Output = F::Output;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Pin::new(&mut self.inner).poll(cx)
}
}
impl<S, Req> Service<Req> for MyMiddleware<S>
where
S: Service<Req>,
{
type Response = S::Response;
type Error = S::Error;
// Use the concrete struct defined above
type Future = MyFuture<S::Future>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}
fn call(&mut self, req: Req) -> Self::Future {
// Pre-processing logic here
let future = self.inner.call(req);
// Wrap the future in our concrete type
MyFuture { inner: future }
}
}