Skip to content

Instantly share code, notes, and snippets.

@max-itzpapalotl
Last active February 25, 2024 14:45
Show Gist options
  • Save max-itzpapalotl/3d37c2e622436583f14cb1d75ed67d36 to your computer and use it in GitHub Desktop.
Save max-itzpapalotl/3d37c2e622436583f14cb1d75ed67d36 to your computer and use it in GitHub Desktop.
25. An HTTP client with the crate

25. An HTTP client with the reqwest crate

In this video I show you how to do HTTP requests with the reqwest crate. I will use the server programs from the previous video 24. as server for this video.

Sending a simple HTTP GET request

We use the reqwest crate as well as the tokio asynchronous runtime:

[dependencies]
reqwest = { version = "0.11.24", features = ["blocking", "json", "rustls-tls"] }
tokio = { version = "1.36.0", features = ["full"] }

Here is the first client program:

#[tokio::main]
async fn main() {
    let res = reqwest::get("http://localhost:8000/api/name/max").await;
    match res {
        Err(e) => {
            println!("An error happened: {:?}", e);
        },
        Ok(resp) => {
            println!("Good response: {:?}", resp);
            println!("{}", resp.text().await.unwrap());
        },
    }
}

Getting the response body as JSON

We need the serde_json crate for this:

[dependencies]
reqwest = { version = "0.11.24", features = ["blocking", "json", "rustls-tls"] }
serde_json = "1.0.113"
tokio = { version = "1.36.0", features = ["full"] }
use serde_json::Value;

#[tokio::main]
async fn main() {
    let res = reqwest::get("http://localhost:8000/api/name/max").await;
    match res {
        Err(e) => {
            println!("An error happened: {:?}", e);
        },
        Ok(resp) => {
            println!("Good response: {:?}", resp);
            let v : Value = resp.json().await.unwrap();
            println!("{}", v);
        },
    }
}

## Sending a POST request with a JSON body

Now we also need the `serde` crate:

```toml
[dependencies]
reqwest = { version = "0.11.24", features = ["blocking", "json", "rustls-tls"] }
serde = { version = "1.0.196", features = ["derive", "serde_derive"] }
serde_json = "1.0.113"
tokio = { version = "1.36.0", features = ["full"] }

And here is the code:

use serde::{Serialize, Deserialize};
use reqwest::Client;

#[derive(Debug, Serialize, Deserialize)]
struct Person {
    name: String,
    age: i32,
}

#[tokio::main]
async fn main() {
    let p = Person{
        name: "Max".to_string(),
        age: 54,
    };
    let client = Client::new();
    let res = client.post("http://localhost:8000/api/person")
        .json(&p)
        .send().await;
    match res {
        Err(e) => {
            println!("An error happened: {:?}", e);
        },
        Ok(resp) => {
            println!("Good response: {:?}", resp);
            let q : Person = resp.json().await.unwrap();
            println!("{:?}", q);
        },
    }
}

Using TLS encryption

See the previous video for instructions on how to create certificates and keys. We use the file ca.pem for server certificate verification from there: https://gist.github.com/max-itzpapalotl/e0943bc83ef48ea0a7fa1abf3b9b553e#setting-up-tls

Here is the client code:

use serde::{Serialize, Deserialize};
use reqwest::{Client, Certificate};

#[derive(Debug, Serialize, Deserialize)]
struct Person {
    name: String,
    age: i32,
}

#[tokio::main]
async fn main() {
    let p = Person{
        name: "Max".to_string(),
        age: 54,
    };
    let certfile = std::fs::read_to_string("ca.pem").unwrap();
    let certificate = Certificate::from_pem(certfile.as_bytes()).unwrap();
    let client = Client::builder().use_rustls_tls()
            .min_tls_version(reqwest::tls::Version::TLS_1_3)
            .tls_built_in_root_certs(false)
            .add_root_certificate(certificate)
            .https_only(true)
            .build().unwrap();
    let res = client.post("https://localhost:8000/api/person")
        .json(&p)
        .send().await;
    match res {
        Err(e) => {
            println!("An error happened: {:?}", e);
        },
        Ok(resp) => {
            println!("Good response: {:?}", resp);
            let q : Person = resp.json().await.unwrap();
            println!("{:?}", q);
        },
    }
}

Using the synchronous (blocking) client

use serde::{Serialize, Deserialize};
use reqwest::{blocking::Client, Certificate};

#[derive(Debug, Serialize, Deserialize)]
struct Person {
    name: String,
    age: i32,
}

fn main() {
    let p = Person{
        name: "Max".to_string(),
        age: 54,
    };
    let certfile = std::fs::read_to_string("ca.pem").unwrap();
    let certificate = Certificate::from_pem(certfile.as_bytes()).unwrap();
    let client = Client::builder().use_rustls_tls()
            .min_tls_version(reqwest::tls::Version::TLS_1_3)
            .tls_built_in_root_certs(false)
            .add_root_certificate(certificate)
            .https_only(true)
            .build().unwrap();
    let res = client.post("https://localhost:8000/api/person")
        .json(&p)
        .send();
    match res {
        Err(e) => {
            println!("An error happened: {:?}", e);
        },
        Ok(resp) => {
            println!("Good response: {:?}", resp);
            let q : Person = resp.json().unwrap();
            println!("{:?}", q);
        },
    }
}

References:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment