Search code examples
rustrust-tokiohyper

Why is there type mismatch when making a POST request using hyper 0.14 over TLS?


I am trying to construct a POST http request using hyper. I am using tokio_rustls to construct a https connector with tls.

The code I am using is:

use hyper::{body::to_bytes, client, Body, Method, Uri,Request};

let mut http = client::HttpConnector::new();
http.enforce_http(false);
//set tls configs.
let mut tls = tokio_rustls::rustls::ClientConfig::new();
// initialize http connector
let https = hyper_rustls::HttpsConnector::from((http, tls));
//prepare client with tls settings.
let client: client::Client<_, hyper::Body> = client::Client::builder().build(https);

let fut = async move {
        let req = Request::builder().method(Method::POST)
            .uri("url")
            .body(())
            .unwrap();
        let res = match client.request(req).await {
            Ok(d) => d,
            Method => {
                println!("Invalid method");
                std::process::exit(1);
            }
            TooLarge => {
                println!("Too large");
                std::process::exit(1);
            }
            Err(e) => {
                println!("unable to post {:?} ", e);
                std::process::exit(1);
            }
        };
        println!("Status:\n{}", res.status());
        println!("Headers:\n{:#?}", res.headers());

        let body: Body = res.into_body();
        let body = to_bytes(body)
            .await
            .map_err(|e| error(format!("Could not get body: {:?}", e)))?;
        println!("Body:\n{}", String::from_utf8_lossy(&body));
        // ...
}

I am getting the following error:

error[E0308]: mismatched types
   --> examples/client.rs:116:40
    |
116 |         let res = match client.request(req).await {
    |                                        ^^^ expected struct `Body`, found `()`
    |
    = note: expected struct `hyper::Request<Body>`
               found struct `hyper::Request<()>`

not sure what I am doing wrong here.


Solution

  • The type mismatch occurred exactly in accordance to the requested types declared. Looking again at the definition of client:

    let client: client::Client<_, hyper::Body> = client::Client::builder().build(https);
    

    The second type parameter of Client (known as B) stands for the expected body type of all requests made by this client. In all subsequent calls to request, the body type must match. In this case, it was defined to hyper::Body, which is also the default type for B. However, the request made next had a body value of type ().

    let req = Request::builder().method(Method::POST)
        .uri("url")
        .body(()) // <--- `()` instead of `Body`
        .unwrap();
    

    If there is no future intention to provide more than an empty body in all requests, then it is safe to change the type parameter B accordingly, or to let the compiler infer it automatically.

    let client: client::Client<_, _> = client::Client::builder().build(https);
    

    Otherwise, the alternative is to provide an empty body through the function Body::empty.

    let req = Request::builder().method(Method::POST)
        .uri("url")
        .body(hyper::Body::empty()) // it's a match now
        .unwrap();