Database lookup in actix-web middleware yields future I can't await

So I'm altering some authentication middleware I've written in actix-web to perform a database lookup, if the session id that is provided isn't in the cache. The problem is that in order to do the lookup I need to await a future so that I can continue to use the data in my middleware to perform the rest of my authentication.

Hopefully there's a simple solution here!

Heres my code:

fn call(&self, request: ServiceRequest) -> Self::Future {
   let cache = request.app_data::<Cache>().unwrap();
   let pool = request.app_data::<Pool>().unwrap();

        //sessions type is: impl Future<Output = Result<SessionObj, Error>>
   let session = session_lookup(Cache, Pool, request)
  
 [...do some stuff with the session]
 

 [...do some stuff to get a csrf token]


  if *csrf_token == *session_token{    
    let res = self.service.call(request);
        Box::pin(async move {
            // forwarded responses map to "left" body
            res.await.map(ServiceResponse::map_into_left_body)  })
    }else{
        let (request, _pl) = request.into_parts();
                let response = HttpResponse::Forbidden()
                    .body(body)
                    .map_into_right_body();
                return Box::pin(async { Ok(ServiceResponse::new(request, response)) })
    }
 }

}

Thanks!

You are halfway there. Notice that the return type for call is Self::Future, which probably you defined it like this:

type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;

The relevant part for your case is that you have to return a pinned box. So let's go back to your code.

In the second half of your code, you are already doing what's expected, i.e. in:

Box::pin(async move {
            // forwarded responses map to "left" body
            res.await.map(ServiceResponse::map_into_left_body)  })

What you want is actually there: An async block where you can await things.

In other words, conceptually you want something like this:

fn call(&self, request: ServiceRequest) -> Self::Future {
  let cache = request.app_data::<Cache>().unwrap();
  let pool = request.app_data::<Pool>().unwrap();
  Box::pin(async move {
    // Do all your async logic and branching here
  })
}
1 Like

I did end up using an async block- but the issue is I need to use the value returned from it in the rest of my code, and the Box::pin also returns some sort of future if I remember correctly. The solution here ended up being a channel!