I needed to read a simple text data from API using reqwest::get
, so I've implemented the following:
#[tokio::main]
async fn process_api() {
let response_text = reqwest::get("https://httpbin.org/anything")
.await.unwrap().text()
.await.unwrap();
println!("{}", response_text);
}
As per documentation
Because this function may panic, its use is generally discouraged.
So I decided to rewrite it in a safer variant to handle error cases explicitly:
#[tokio::main]
async fn process_api() {
let response = reqwest::get("https://httpbin.org/anything").await;
match response {
Ok(resp) => {
match resp.text().await {
Ok(response_text) => {
println!("{}", response_text);
}
Err(e) => {
println!("Error with API while fetching text {}", e)
}
}
}
Err(e) => {
println!("Error with API {}", e)
}
}
}
But that piece of code looks way too verbose
I also tried if let
construct:
#[tokio::main]
async fn process_api() {
let response = reqwest::get("https://httpbin.org/anything").await;
if let Ok(resp) = response {
if let Ok(response_text) = resp.text().await {
println!("{}", response_text);
} else {
println!("Error with API while fetching text!")
}
} else {
println!("Error with API");
}
}
But even though it looks shorter there would be no Error
in logs. So it seems even worse in this particular case.
My question - is there a better way to write this?
Note, that I don't want to panic
all the way to main
but rather gracefully log potential errors.
I honestly tried different variations of map*
/and_then
and the "best" I got was:
#[tokio::main]
async fn process_api() {
let response = reqwest::get("https://httpbin.org/anything").await;
response
.map(|resp| async move {
match resp.text().await {
Ok(response_text) => {
println!("{}", response_text);
}
Err(e) => {
println!("Error with API {}", e)
}
}
}).unwrap().await;
}
but it just looks horrendous.