Calling a Service inside another Service (Tower, Axum)

I would like to implement a logic that authenticates a user and then decides if they are authorized to view a resource. I would like to achieve that feature by implementing two services:

I list only Future implementations below for the sake of brevity.

Authenticate Service

Service attempts to retrieve a user from DB.

impl Future for AuthenticateServiceFuture {
    type Output = Result<User, Option<UserError>>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        if self.public_id.is_none() {
            return Poll::Ready(Err(None));

        let public_id = self.public_id.unwrap();
        let future = User::get(GetUserBy::PublicId(public_id.as_str()), &self.db_pool);
        let mut boxed_future = Box::pin(future);
        let polled_result = boxed_future.as_mut().poll(cx);

        match polled_result {
            Poll::Ready(result) => {
                if let Ok(user) = result {
                } else {
            Poll::Pending => Poll::Pending,

Where User::get is another Future.

Protect Route Service

Service wraps some other service. It also retrieves a User via AuthenticateService call. If the user is authenticated, access is granted; the inner service response is returned. Otherwise a redirect should be made.

impl<F, ReqBody, ResBody> Future for ProtectRouteResponseFuture<F, ReqBody>
    F: Future<Output = BoxFuture<'static, Result<Response<ResBody>, Redirect>>>,
    type Output = BoxFuture<'static, Result<Response<ResBody>, Redirect>>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let this = self.project();
        let inner_service = ready!(this.inner.poll(cx));

        Box::pin(async {
            match this.authenticate_service.poll_ready(cx) {
                Poll::Ready(Ok(())) => this
                    .and_then(|_| Ok(inner_service))
                Poll::Ready(Err(Some(user_error))) => Err(Redirect::to("/auth")),
                Poll::Ready(Err(None)) => Err(Redirect::to("/auth")),
                Poll::Pending => Err(Redirect::to("/auth")),

However, the code does not compile. It seems to me that I misunderstand how Services can call each other and how, in turns, I should describe Future Output types. Unfortunately, articles from Tower did not help ://

You shouldn't manually implement the Future trait and especially not in this way. The poll method of a Future is called repeatedly until it completes, and the Future itself should store any temporary state inside itself. So for example:

This is making a new get request every time the Future is polled, which is not what you want, you want a single get request which is continuously polled with your Future, which is very cumbersome to write manually.

Here you're not even returning a Poll, but a whole different Future.

For now (at least until we get async fn in traits) your service's Future (and not the Future's output) should just be a BoxFuture<'static, Result<Response<ResBody>, Request>>

Alright, how would you write down (without so much of a detail) a scenario that does the following:

Service A wraps some inner Service B. Service A makes a call to Service C before resolving with a response made by Service B, if Service C allows to do so. If Service C succeeds, Service A returns with Response from Service B. Otherwise it builds its own Response and returns it.

How would Future fn poll return type look like in that case, given that i need to .await some other Service?

It should be something like this (note the comments though for why this doesn't fully work):

struct ServiceA {
    service_b: ServiceB,
    service_c: ServiceC,
impl<Req> Service<Req> for ServiceA {
    type Response = <ServiceB as Service<Req>>::Response;
    type Error = <ServiceB as Service<Req>>::Error;
    type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
    fn poll_ready(
        &mut self, 
        cx: &mut Context<'_>
    ) -> Poll<Result<(), Self::Error>> {
        // Might want to `poll_ready` on `service_b`/`service_c` here.
    fn call(&mut self, req: Req) -> Self::Future {
        // Note that you can't use `self` in the `async` block due to it
        // having to be `'static`.
        // Hence you have to prepare the futures here.
        // Also, this is invalid because `req` is moved in the first `call`.
        // You'll need to rethink what you want to do here.
        let future_b =;
        let future_c =;
        Box::new(async move {
            // Put here your `async` code with all the `.await`s you need

My point is that you don't implement Future and hence you don't write a poll function.

Rethinking this, maybe you want a middleware? Try checking out the axum::middleware module, in particular you might be interested in the from_fn function.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.