7

I'm writing a "hello world" HTTP server with Hyper, however I am not able to find the Server and rt modules when trying to import them.

When invoking cargo run, then I see this error message:

26 |     let server = hyper::Server::bind(&addr).serve(router);
   |                         ^^^^^^ could not find `Server` in `hyper`

I must be missing something obvious about Rust and Hyper. What I am trying to do is writing something as dry/simple as possible with just the HTTP layer and some basic routes. I would like to include as little as possible 3rd party dependencies e.g avoiding Tokio which I think involves async behavior, but I am not sure about the context as I am new to Rust.

Looks like I must use futures, so I included this dependency and perhaps futures only work with the async reserved word (which I am not sure if it comes from Tokio or Rust itself).

What confuses me is that in the Hyper examples I do see imports like use hyper::{Body, Request, Response, Server};, so that Server thing must be there, somewhere.

These are the dependencies in Cargo.toml:

hyper = "0.14.12"
serde_json = "1.0.67"
futures = "0.3.17"

This is the code in main.rs:

use futures::future;
use hyper::service::service_fn;
use hyper::{Body, Method, Response, StatusCode};
use serde_json::json;

fn main() {
    let router = || {
        service_fn(|req| match (req.method(), req.uri().path()) {
            (&Method::GET, "/foo") => {
                let mut res = Response::new(
                    Body::from(json!({"message": "bar"}).to_string())
                );
                future::ok(res)
            },
            (_, _) => {
                let mut res = Response::new(
                    Body::from(json!({"content": "route not found"}).to_string())
                );
                *res.status_mut() = StatusCode::NOT_FOUND;
                future::ok(res)
            }
        })
    };

    let addr = "127.0.0.1:8080".parse::<std::net::SocketAddr>().unwrap();
    let server = hyper::Server::bind(&addr).serve(router); // <== this line fails to compile
    // hyper::rt::run(server.map_err(|e| {
    //     eprintln!("server error: {}", e);
    // }));
}

How do I make the code above compile and run?

TPPZ
  • 4,447
  • 10
  • 61
  • 106

1 Answers1

3

According to documentation, you are missing one module namespace in your call hyper::server::Server:

let server = hyper::server::Server::bind(&addr).serve(router)

In order to use server you need to activate the feature flag in cargo:

hyper = { version = "0.14.12", features = ["server"] }
Netwave
  • 40,134
  • 6
  • 50
  • 93
  • "could not find `server` in `hyper`". Weird. Am I supposed to include any hidden dependency - is `hyper = "0.14.12"` enough? – TPPZ Sep 03 '21 at 10:41
  • 1
    OK, and now the compiler is saying "could not find `Server` in `server`". No idea what is going on :( – TPPZ Sep 03 '21 at 10:59
  • 1
    `bind` is supported on (crate features http1 or http2) and crate feature tcp only. → add those to the feature flags. – Jmb Sep 03 '21 at 13:45
  • Although there's something missing in the docs: the whole `Server` struct is only available on feature `tcp`, but this is not mentioned in the docs. – Jmb Sep 03 '21 at 13:46
  • 2
    Had to add all the 3 of them: `hyper = { version = "0.14.12", features = ["http1", "server", "tcp"] }`. However now there's an issue with the `router` not implementing a Trait or something, but I haven't seen any doc or example providing a router much more complex than what I wrote above: "the trait `for<'a> Service<&'a AddrStream>` is not implemented for `[closure@src/main.rs:7:18: 23:6]`" – TPPZ Sep 03 '21 at 14:05