logo MSJO.kr

rust, async reqwest

2022-02-16
MsJ

Rust 프로그램에서 HTTP, Rest API(webapi)를 사용하기 위해 reqwest 패키지를 활용한 기본적인 아래의 예제는 blocking 방식과 async로 확장한 방법을 보여준다.

예제에 필요한 기본적인 패키지는 reqwest 외에 tokio, serde를 사용한다. 예제에 사용한 베이스 코드는 Proful Sadangi(Youtube)1를 참고2하였다.

환경구성(vscode)
#Cargo.toml
[dependencies]
reqwest = { version = "0.11", features = ["blocking","json"] }
tokio = { version = "1.15.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.74"

#rustfmt.toml
max_width = 200
fn_args_layout = "Compressed"
use_small_heuristics = "Max"

#.cargo/config : static compile option
[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]
기본 Blocking 예제
fn main() {
    let posts_url = "https://jsonplaceholder.typicode.com/posts";

    // [1] blocking reqwest GET call
    // let mut resp = reqwest::blocking::get(posts_url).unwrap();
    // resp.copy_to(&mut std::io::stdout()).unwrap();

    // [2] blocking reqwest GET call
    let resp = reqwest::blocking::get(posts_url).unwrap();
    let resp_url = resp.url().clone().to_string();
    let resp_host = resp.url().host().clone().unwrap().to_string();
    let resp_status = resp.status().clone().to_string();

    let resp_header_result;

    let resp_header = resp.headers().get("content-type").clone();

    if resp_header.is_some() {
        resp_header_result = resp_header.clone().unwrap().to_str().unwrap();
    } else {
        resp_header_result = "Error";
    }

    println!("{}, {}, {}, {}", resp_url, resp_host, resp_status, resp_header_result.to_string());

    // [3] blocking reqwest GET call    
    let post_res = reqwest::blocking::get(posts_url).unwrap().text().unwrap();

    println!("{}", post_res);
}
async 기본 예제
use reqwest::Error;
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, Serialize)]
struct Post {
    #[serde(rename = "userId")]
    user_id: i32,
    id: i32,
    title: String,
    body: String,
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    // [1]
    let posts_url = "https://jsonplaceholder.typicode.com/posts";
    let resp = reqwest::get(posts_url).await.unwrap();
    let posts: serde_json::Value = resp.json().await.unwrap();
    println!("{}", &posts);
    println!("{}", &posts[10]["body"]);
    println!("{}", &posts[10]["body"].as_str().unwrap());

    // [2]
    let posts_url = "https://jsonplaceholder.typicode.com/posts";
    let resp = reqwest::get(posts_url).await.unwrap();
    let posts: Vec<Post> = resp.json().await.unwrap();
    for post in posts {
        println!("{:?} {:?} {:?} {:?}", post.user_id, post.id, post.title, post.body);
    }

    // [3]
    let posts_url = "https://jsonplaceholder.typicode.com/posts";
    let post_map = serde_json::json!({
        "userId" : "1000",
        "title" : "foo",
        "body" : "bar",
    });
    let client = reqwest::Client::new();
    let resp = client.post(posts_url).json(&post_map).send().await.unwrap();
    let post_json: serde_json::Value = resp.json().await.unwrap();
    println!("{:?}", serde_json::to_string_pretty(&post_json).unwrap());

    // [4]
    let posts_url = "https://jsonplaceholder.typicode.com/posts";
    let resp = reqwest::get(posts_url).await?.json::<Vec<Post>>().await;
    // println!("{:?}", serde_json::to_string_pretty(&resp));
    if resp.is_ok() {
        println!("{:?}", serde_json::to_string_pretty(&resp.ok()).unwrap());
    } else {
        println!("xxxxxxxxxxxxxx");
    }

    Ok(())
}
예제 1
use reqwest::Error;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct IpInfo {
    ip: String,
    city: String,
    region: String,
    country: String,
    loc: String,
    org: String,
    postal: String,
    timezone: String,
    readme: String,
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    let res_ipinfo1 = reqwest::get("http://ipinfo.io/json").await; //.text().await?;

    if res_ipinfo1.is_ok() {
        let result = res_ipinfo1?.text().await?;
        if result.contains("error") {
            println!("Error Message : {}", result.replace("\n", ""));
        } else {
            println!("{}\n", result);
        }
    } else {
        if let Err(e) = res_ipinfo1 {
            println!("Error Message : {}", e);
        }
    }

    let res_ipinfo2 = reqwest::get("http://ipinfo.io/json").await; // ?.json::<HashMap<String, String>>().await?;

    if res_ipinfo2.is_ok() {
        let a = res_ipinfo2?.json::<HashMap<String, String>>().await;

        if a.is_ok() {
            let b = a?;
            let mut items: Vec<_> = b.iter().collect();
            items.sort();

            for (key, value) in items.iter() {
                println!("{} : {}", key, value);
            }
        } else {
            println!("zzzzzzzzzzzz");
        }
    } else {
        println!("yyyyyyyyyyyyyyyy");
    }

    Ok(())
}
예제 2
use reqwest::Error;
use serde::Deserialize;

#[derive(Deserialize, PartialEq, Debug)]
struct HttpBin {
    slideshow: Show,
}

#[derive(Deserialize, PartialEq, Debug)]
struct Show {
    author: String,
    date: String,
    slides: Vec<Slide>,
    title: String,
}

#[derive(Deserialize, PartialEq, Debug)]
struct Slide {
    items: Option<Vec<String>>,
    title: String,
    r#type: String,
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    let res = reqwest::get("https://httpbin.org/json").await;
    if res.is_ok() {
        println!("{}", res?.text().await?);
    } else if let Err(e) = res {
        println!("Error Message : {}", e);
    }

    println!("-------------------------------------");

    let res_httpbin = reqwest::get("https://httpbin.org/json").await?.json::<HttpBin>().await?;

    // println!("slideshow : {:?}\n", res_httpbin.slideshow);
    println!("author : {}", res_httpbin.slideshow.author);
    println!("date : {}", res_httpbin.slideshow.date);
    println!("title : {}", res_httpbin.slideshow.title);

    println!("-------------------------------------");

    for (k1, v1) in res_httpbin.slideshow.slides.iter().enumerate() {
        for v2 in v1.items.iter() {
            for (k3, v3) in v2.iter().enumerate() {
                println!("slides[{}] : items[{}] : {}", k1, k3, v3);
            }
        }

        println!("slides[{}] : title : {}", k1, v1.title);
        println!("slides[{}] : type : {}", k1, v1.r#type);
    }

    Ok(())
}

// 결과
// {
//     "slideshow": {
//       "author": "Yours Truly", 
//       "date": "date of publication", 
//       "slides": [
//         {
//           "title": "Wake up to WonderWidgets!", 
//           "type": "all"
//         }, 
//         {
//           "items": [
//             "Why <em>WonderWidgets</em> are great", 
//             "Who <em>buys</em> WonderWidgets"
//           ], 
//           "title": "Overview", 
//           "type": "all"
//         }
//       ], 
//       "title": "Sample Slide Show"
//     }
//   }
//  
//   -------------------------------------
//   author : Yours Truly
//   date : date of publication
//   title : Sample Slide Show
//   -------------------------------------
//   slides[0] : title : Wake up to WonderWidgets!
//   slides[0] : type : all
//   slides[1] : items[0] : Why <em>WonderWidgets</em> are great
//   slides[1] : items[1] : Who <em>buys</em> WonderWidgets
//   slides[1] : title : Overview
//   slides[1] : type : all
추천 강좌 및 문서
Reference
  1. Proful Sadangi, “reqwest Rust Tutorial”
  2. DebugJO, “rust_get_json.rs”

Prεv(Θld)   Nεxt(Nεw)
Content RustLang.kr
Search     RSS Feed     BY-NC-ND