AWS lambda rust - how to make a function to return outer closure?

474 views Asked by At

I am using rust-aws-lambda project. My use case is with Lambda as an API Gateway Proxy. Additionally I am using closures as explained in this example, as I want to use shared resources such as clients and secret value (retrieved from AWS Secrets Manager) in my lambda code.

The issue I am struggling with for long time is how I can abstract the closures into another helper function. I want the function to return the outer closure in this case, for example. I have tryd but I cannot get Rust compiler to let me do this.

The both closures are within main function. Per the listed example, my inner closure is defined something like this:

let handler_func_closure = move |event: ApiProxyRequest| async move {
    ...
    Ok::<_, Error>(success_resp)
};

These are my relevant imports in the code:

use lambda_http::{service_fn, Body, Error, IntoResponse, Request as ApiProxyRequest, RequestExt};
use lambda_http::tower::util::ServiceFn;

I have below closure which I have defined in async main function in main.rs, which is working for me so far.

let outer_closure = move |event: ApiProxyRequest| async move {
    match handler_func_closure(event).await {
        Ok(s) => Ok(s.into_response()),
        Err(e) => Ok(http::Response::builder()
          .header(http::header::CONTENT_TYPE, "application/json")
          .status(400)
          .body(
            serde_json::to_string(&json!({"error": &err.to_string()}))
                .expect("unable to serialize serde_json::Value")
                .into(),
        )
          .expect("unable to build http::Response")),
    }
};

Where into_response() is satisfied by a struct implementing from trait IntoResponse.

So basically what I'm trying to do is make a function to return closure that can be passed in to service_fn. Below is my attempt so far - but it's not satisfy Rust compiler currently.

pub fn get_service_fn<T, T2, F, F2, I: IntoResponse>(handler_func_closure: T) -> ServiceFn<T2>
    where T: Fn(http::Request<Body>) -> F + Send + Sync,
    T2: Fn(lambda_http::Request) -> F2,
        F2: Future<Output=crate::Result<http::Response<Body>>>,
          F: Future<Output=crate::Result<I>> + Send {
    let outer_closure = move |event: ApiProxyRequest| async move {
        match handler_func_closure(event).await {
            Ok(s) => Ok(s.into_response()),
            Err(e) => failure(Box::new(e), None),
        }
    };

    service_fn(outer_closure)
};

I have seen other question asked on how can function return closure, but I cannot seem to get it to work in this case. I am curious to know if anyone able to get this to work where an outer closure returned by a function can be passed in to service_fn.

I feel like I've spent countless hours in trying to figure this out, but I've been unable to make it work. I'm not entirely sure whether this is possible in Rust to be honest, but I'd be curious if anyone has an idea how to approach this.


Edit: This is the compiler error I'm getting in case it's helpful:

error[E0308]: mismatched types
   --> src/bin/my_lambda/main.rs:197:16
    |
185 |    pub fn get_service_fn<T, T2, F, F2, I: IntoResponse>(handler_func_closure: T) -> ServiceFn<T2>
    |                             -- this type parameter
...
190 |        let outer_closure = move |event: ApiProxyRequest| async move {
    |  __________________________-________________________________________-
    | | _________________________|
    | ||
191 | ||         match handler_func_closure(event).await {
192 | ||             Ok(s) => Ok(s.into_response()),
193 | ||             Err(e) => failure(Box::new(e), None),
194 | ||         }
195 | ||     };
    | ||     -
    | ||_____|
    | |______the found closure
    |        the found `async` block
196 | 
197 |        service_fn(outer_closure)
    |                   ^^^^^^^^^^^^^ expected type parameter `T2`, found closure
    |
   ::: /Users/rnag/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/future/mod.rs:61:43
    |
61  |    pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
    |                                              ------------------------------- the found opaque type
    |
    = note: expected type parameter `T2`
                      found closure `[closure@src/bin/my_lambda/main.rs:190:25: 195:6]`
    = help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `T2`
0

There are 0 answers