Skip to content

[RFC] Wrap interface for tower::Service<Request> #404

Closed
@nmoutschen

Description

@nmoutschen

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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions