Call async function from Actix Web middleware

I'm trying to write a middleware in Actix Web that will call an async function and, depending on the response, let the request flow as usual or return early.

Here's a simplified version of my code:

impl<S, B> Service for MyLittleMiddleware<S> ... {
 
  ...
  type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;

  fn call(&mut self, req: ServiceRequest) -> Self::Future {

    Box::pin(async move {
       // the async logic here
    }
  }
}

The issue is that I can't call self.service.call(req) from within the async block to allow the request flow as usual, because the reference to self in the function does not have a static lifetime.

I have tried to reduce the noise as much as possible, but no matter what I try, this limitation just sticks and does not let me go ahead. For example, if I move the call to self.service.call(req) outside the async block, it will move req with it and render the rest of the code unusable. It might be worth mentioning that the async function that I'm calling is in the application's data, hence the need to access the request from within the async block.

It would be great if we could return a response without having to mutate the request :frowning: .

1 Like

What information do you need from req?

I need to access app_data from it:

let services = req.app_data::<web::Data<Services>>().unwrap().clone();

I have made some progress (I hope, hahahah) by not needing to access req to return the failed response. I changed this:

ok(req.into_response(HttpResponse::NotFound().finish().into_body()))

to this:

err(MyLittleError::NotFound.into())

Since MyLittleError implements ResponseError. Now the compiler is compaining about the fact that I'm returning a value referencing data owned by the current function:

 | /     match a_result {
 | |       Ok(value) => {
 | |
 | |         services.my_little_service.do_something(value);
 | |                 -------- `services` is borrowed here
 | |
 | |       Err(_) => Box::pin(ok(req.into_response(HttpResponse::NotFound().finish().into_body())))
 | |     }
 | |_____^ returns a value referencing data owned by the current function

I just solved it. Thanks for the rubber ducking, Alice :smiley: .

For reference, this is the simplified code:

impl<S, B> Service for MyLittleMiddleware<S> ... {

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

  fn call(&mut self, req: ServiceRequest) -> Self::Future {
    let normal_response = self.service.call(req);

    Box::pin(async move {
       // the async logic here
       // use err(MyLittleError::NotFound.into()).await instead of mutating the request
    }
  }
}

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.