Description
Remark: This is a follow-up to #374 as I'm currently implementing it. See #401 for progress.
Background
Right now, the current implementation in lambda_http::handler
takes a handler function that takes a Request
and returns an IntoResponse
implementation. This allows to pass the wrapped handler function into lambda_runtime::run
directly. However, it has a few limitations.
First, Request
and IntoResponse
aren't Deserialize
and Serialize
, but lambda_runtime::run
require those traits. It means we have to pass through an intermediate Adapter
to transform the requests and responses. This is currently handled by lambda_http::handler
. As a consequence, the current implementation doesn't allow taking a lambda_runtime::Handler
implementation directly. It offers a lambda_http::Handler
, which implements it.
This causes some switching away from custom Handler
traits towards tower::Service
. Ideally, we should allow users to provide tower::Service<Request>
implementations, and handle the transformation under the hood on their behalf. However, due to lambda_runtime::run
's signature, we cannot do that as-is. We also cannot implement Deserialize
and Serialize
for Request
and Response
, as those are all foreign traits and types.
Proposition 1: extension trait for Service<Request>
use tower::Service;
use lambda_http::{Request, ServiceExt};
#[derive(Default)]
struct MyHandler;
impl Service<Request> for MyHandler {
// skipped
}
#[tokio::main]
async fn main() -> Result<(), Error> {
// Use .into_runtime() to transform the Service
lambda_runtime::run(MyHandler::default().into_runtime()).await
}
Proposition 2: create a lambda_http::run
wrapper
use tower::Service;
use lambda_http::Request;
#[derive(Default)]
struct MyHandler;
impl Service<Request> for MyHandler {
// skipped
}
#[tokio::main]
async fn main() -> Result<(), Error> {
// Use lambda_http::run to wrap the Service
lambda_http::run(MyHandler::default()).await
}
Proposition 3: your idea here
If you have an idea that gives a cleaner interface, let me know!