tower-http icon indicating copy to clipboard operation
tower-http copied to clipboard

"Example server" example in the docs doesn't actually run a server.

Open kevincox opened this issue 1 year ago • 2 comments
trafficstars

Bug Report

The docs have a section "Example server" section which claims to "run that service using hyper."

https://github.com/tower-rs/tower-http/blob/3f98dc19bc6c70aa6e4912b63538d89443f03b19/tower-http/src/lib.rs#L12-L85

However this doesn't seem to use Hyper at all and doesn't actually run any server. There is just hidden code to send a request to the Service from Rust.

Description

It seems that either the wording around the example should be updated or the example should be fixed to actually run a server.

It would be nice to have a minimal server example, as it seems like right now the way to do this is to use a "full featured" framework like axum or warp just to run a tower Service.

kevincox avatar Sep 05 '24 11:09 kevincox

I think this is as minimal as it gets when not using something like axum / warp.

Want to incorporate that into the docs in a PR?

jplatte avatar Sep 05 '24 19:09 jplatte

similar minimal version but without serving a file:

main.rs:

use std::convert::Infallible;
use std::net::SocketAddr;

use http_body_util::Full;
use hyper::body::Bytes;
use hyper::{Request, Response};
use tokio::net::TcpListener;
use tower::ServiceBuilder;

async fn handle(_req: Request<hyper::body::Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {
    Ok(Response::new(Full::new(Bytes::from("hello, world"))))
}

#[tokio::main]
async fn main() {
    let tower_service = ServiceBuilder::new().service_fn(handle);
    let hyper_service = hyper_util::service::TowerToHyperService::new(tower_service);

    let addr = SocketAddr::from(([0, 0, 0, 0], 5000));
    let listener = TcpListener::bind(addr).await.unwrap();

    loop {
        let (stream, _) = listener.accept().await.unwrap();

        let io = hyper_util::rt::TokioIo::new(stream);
        let service_clone = hyper_service.clone();

        tokio::task::spawn(async move {
            if let Err(err) =
                hyper_util::server::conn::auto::Builder::new(hyper_util::rt::TokioExecutor::new())
                    .serve_connection(io, service_clone)
                    .await
            {
                eprintln!("server error: {}", err);
            }
        });
    }
}

Cargo.toml:

[package]
name = "hyper-hello-world"
version = "0.1.0"
edition = "2021"

[dependencies]
bytes = { version = "1", default-features = false }
hyper = { version = "1", default-features = false }
http-body-util = { version = "0.1", default-features = false }
hyper-util = { version = "0.1", features = ["http1", "service", "server", "tokio"], default-features = false }
tokio = { version = "1", features = ["rt-multi-thread", "macros"], default-features = false }
tower = { version = "0.5", default-features = false, features = ["util"] }
tower-http = { version = "0.6", default-features = false }

francoposa avatar Sep 29 '24 01:09 francoposa