10

Rust - Reqwest examples

 3 years ago
source link: https://dev.to/pintuch/rust-reqwest-examples-10ff
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Introduction

There are 3 things that need to happen:

  • Building a client that can be reused across multiple requests
  • Performing the execution of the network request
  • Parsing the response
use std::collections::HashMap;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Build the client using the builder pattern
    let client = reqwest::Client::builder()
        .build()?;

    // Perform the actual execution of the network request
    let res = client
        .get("https://httpbin.org/ip")
        .send()
        .await?;

    // Parse the response body as Json in this case
    let ip = res
        .json::<HashMap<String, String>>()
        .await?;

    println!("{:?}", ip);
    Ok(())
}
Enter fullscreen modeExit fullscreen mode

Instead of parsing the json body as a dynamic hash-map, you could use a well-defined struct

use serde::Deserialize;

#[derive(Deserialize, Debug)]
struct Ip {
    origin: String
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Build the client using the builder pattern
    let client = reqwest::Client::builder()
        .build()?;

    // Perform the actual execution of the network request
    let res = client
        .get("https://httpbin.org/ip")
        .send()
        .await?;

    // Parse the response body as Json in this case
    let ip = res
        .json::<Ip>()
        .await?;

    println!("{:?}", ip);
    Ok(())
}
Enter fullscreen modeExit fullscreen mode

Query Strings

let client = reqwest::Client::builder()
    .build()?;

let res = client
    .get("http://httpbin.org")
    .query(&[("foo", "bar")])
    .send()?;
Enter fullscreen modeExit fullscreen mode

POST JSON Data

The json(..) method on the RequestBuilder takes any value that can be serialized into JSON such as a HashMap or a Struct.

let mut map = HashMap::new();
map.insert("foo", "bar");
map.insert("buzz", "blah");

...
.json(&map)
Enter fullscreen modeExit fullscreen mode
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Debug, Serialize, Deserialize)]
struct Person {
    first_name: String,
    last_name: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct PersonResponse {
    data: String,
    method: String,
    headers: HashMap<String, String>
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let p = Person { 
        first_name: "Foo".into(),
        last_name: "Bar".into(),
    };

    let res = reqwest::Client::new()
        .post("https://httpbin.org/anything")
        .json(&p)
        .send()
        .await?;

    let js = res
        .json::<PersonResponse>()
        .await?;

    let person: Person = serde_json::from_str(&js.data)?;
    println!("{:#?}", person);

    println!("Headers: {:#?}", js.headers);
    Ok(())
}

Enter fullscreen modeExit fullscreen mode

POST Form data

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct Person {
    first_name: String,
    last_name: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let p = Person { 
        first_name: "Foo".into(),
        last_name: "Bar".into(),
    };

    let res = reqwest::Client::new()
        .post("https://httpbin.org/anything")
        .form(&p)
        .send()
        .await?;

    let t = res
        .text()
        .await?;

    println!("{}", t);

//  $ cargo run
//      Finished dev [unoptimized + debuginfo] target(s) in 0.09s
//       Running `target/debug/reqwest-tut`
//  {
//    "args": {}, 
//    "data": "", 
//    "files": {}, 
//    "form": {
//      "first_name": "Foo", 
//      "last_name": "Bar"
//    }, 
//    "headers": {
//      "Accept": "*/*", 
//      "Content-Length": "28", 
//      "Content-Type": "application/x-www-form-urlencoded", 
//      "Host": "httpbin.org", 
//      "X-Amzn-Trace-Id": "Root=1-60453174-384d97870199933007fbb388"
//    }, 
//    "json": null, 
//    "method": "POST", 
//    "origin": "125.125.104.53", 
//    "url": "https://httpbin.org/anything"
//  }
//  
//  
    Ok(())
}

Enter fullscreen modeExit fullscreen mode

Request Headers

You can set the headers by calling the header(.., ..) method on the request

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::builder()
        .build()?;

    let res = client
        .post("https://httpbin.org/anything")
        .body("arbitrary text")
        .header("X-Person-First", "Foo!")
        .header("X-Person-Last", "Bar!!")
        .send()
        .await?;

    let t = res
        .text()
        .await?;

    println!("{}", t);
// {
//   "args": {}, 
//   "data": "arbitrary text", 
//   "files": {}, 
//   "form": {}, 
//   "headers": {
//     "Accept": "*/*", 
//     "Content-Length": "14", 
//     "Host": "httpbin.org", 
//     "X-Amzn-Trace-Id": "Root=1-604538df-218a5bb97264e7130c298b23", 
//     "X-Person-First": "Foo!", 
//     "X-Person-Last": "Bar!!"
//   }, 
//   "json": null, 
//   "method": "POST", 
//   "origin": "49.206.4.160", 
//   "url": "https://httpbin.org/anything"
// }

    Ok(())
}

Enter fullscreen modeExit fullscreen mode

You can also set default headers on the client that can be overriden while making individual requests

use reqwest::header;

#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
    let mut headers = header::HeaderMap::new();
    headers.insert("X-HEADER-1", header::HeaderValue::from_static("val1"));
    headers.insert("X-HEADER-2", header::HeaderValue::from_static("val2"));

    let client = reqwest::Client::builder()
        .default_headers(headers)
        .build()?;

    let res = client
        .get("https://httpbin.org/anything")
        .body("whatever")
        .header("X-HEADER-1", "overriden val1")
        .send()
        .await?;

    println!("{}", res.text().await?);

    // {
    //   "args": {},
    //   "data": "whatever",
    //   "files": {},
    //   "form": {},
    //   "headers": {
    //     "Accept": "*/*",
    //     "Content-Length": "8",
    //     "Host": "httpbin.org",
    //     "X-Amzn-Trace-Id": "Root=1-60453dad-429e59a434bd460b0a48e7d5",
    //     "X-Header-1": "overriden val1",
    //     "X-Header-2": "val2"
    //   },
    //   "json": null,
    //   "method": "GET",
    //   "origin": "49.206.4.160",
    //   "url": "https://httpbin.org/anything"
    // }

    Ok(())
}
Enter fullscreen modeExit fullscreen mode

Status Code

#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
    let client = reqwest::Client::builder().build()?;

    let res = client
        .get("https://httpbin.org/status/400")
        .send()
        .await?;

    match res.status() {
        reqwest::StatusCode::BAD_REQUEST => println!(
            "content-length:{:?} server:{:?}", 
            res.headers().get(reqwest::header::CONTENT_LENGTH),
            res.headers().get(reqwest::header::SERVER),
        ),
        status => println!("status: {}", status),
    }

    // content-length:Some("0") server:Some("gunicorn/19.9.0")
    Ok(())
}
Enter fullscreen modeExit fullscreen mode

Timeouts

Client Timeout

let client = reqwest::Client::builder()
    .timeout(std::time::Duration::from_millis(500))
    .build()?;

Enter fullscreen modeExit fullscreen mode

Connect Timeout

let client = reqwest::Client::builder()
    .connect_timeout(std::time::Duration::from_millis(100))
    .build()?;
Enter fullscreen modeExit fullscreen mode

Request Timeout

let res = client
    .get(&url)
    .timeout(std::time::Duration::from_millis(500))
    .send()
    .await;
Enter fullscreen modeExit fullscreen mode

Download data

use std::fs::File;
use std::io;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::builder().build()?;

    let res = client
        .get("https://httpbin.org/image/png")
        .send()
        .await?
        .bytes()
        .await?;

    let mut data = res.as_ref();

    let mut f = File::create("i.png")?;

    io::copy(&mut data, &mut f)?;

    Ok(())
}

// $ file i.png 
// i.png: PNG image data, 100 x 100, 8-bit/color RGB, non-interlaced 
Enter fullscreen modeExit fullscreen mode
Dependency configuration for the samples
[dependencies]
reqwest = { version = "0.11", features = ["json", "blocking", "cookies"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1.0" 
futures = "0.3"
Enter fullscreen modeExit fullscreen mode

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK