Reqwest公式の説明は初学者を混乱させる
組み込み機器に近い産業PCにAPIを作る必要があってRustを学び始めた者です。
actix-web上でreqwestを使う場面が出てきて実装しようと思ったらコンパイラに怒られまくりました。
Rust初学者がハマってしまうところがあったので備忘録として書きます。
かなり試行錯誤と勘違いがあった(pythonのrequestsと同じような使い方だと思っていた)ので初学者を対象に情報共有をします。
公式さんよ、前提を教えてくれよ
reqwest公式の説明から下記の書き方をやりがちですが、これは動きません。
なぜならreqwestは非同期処理(async main()みたいなやつ)がデフォルトに変更したからです!!
警告
下記のコードは動きません!!
//うごきません!!
fn main(){
let body = reqwest::get("https://www.rust-lang.org")
.await?
.text()
.await?;
println!("body = {:?}", body);
}
前提条件
まず最初に公式通りのコードを使いたい場合はreqwestと共にtokioが必要になります。
通常通りに同期処理で使いたい場合はCorgo.tomlに"features = ["blocking"]"を追加する必要があります。
Cargo.toml
[package]
name = "reqwest-practice"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
reqwest = { version = "*", features = ["blocking"] }
tokio = { version = "*", features = ["full"] }
通常の同期処理で使いたい場合
fn main() {
let url = "https://www.rust-lang.org";
let rc = reqwest::blocking::get(url).unwrap(); //同期処理にするためreqwest::blockingから呼び出す。
let contents = rc.text().unwrap();
println!("{}", contents);
}
公式のドキュメントで説明されている非同期処理の場合
tokioを使う必要があります。その説明がないのでRust初学者の鬼門です。
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let url = "https://www.rust-lang.org";
let contents = reqwest::get(url).await?.text().await?;
println!("{:?}", contents);
Ok(())
}
非同期処理で関数を分割した場合
async fn sub() -> Result<(), Box<dyn std::error::Error>> {
let url = "https://www.rust-lang.org";
let contents = reqwest::get(url).await?.text().await?;
println!("{:?}", contents);
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
sub().await?;
Ok(())
}
actix_webでreqwestを利用した場合
自分が必要だったので備忘録的に残しておきます。
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};
async fn sub() -> Result<String, reqwest::Error> {
let url = "https://www.rust-lang.org";
let contents = reqwest::get(url).await?.text().await?;
println!("{:?}", contents);
Ok(contents)
}
#[get("/")]
async fn hello() -> impl Responder {
sub().await.unwrap();
HttpResponse::Ok().body("Hello world!")
}
#[post("/echo")]
async fn echo(req_body: String) -> impl Responder {
HttpResponse::Ok().body(req_body)
}
async fn manual_hello() -> impl Responder {
HttpResponse::Ok().body("Hey there!")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.service(hello)
.service(echo)
.route("/hey", web::get().to(manual_hello))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
async fn main()-> std::io::Result<()>
Rust初学者のため、上記のコードになぜ戻り値が入ってくるのか、理屈がわかっていなかったりします。
2024/07/27 追記
[?]で記述したい場合にResult型で自動的にError排出する際に必要だから。