I'm struggling with error handling cleanly in Rust. Say I have a function that is propogating multiple error types with Box<dyn Error>. To unwrap and handle the error, I'm doing the following:
fn main() {
let json =
get_json_response(format!("{}{}", BASE_URL, LOGIN_URL).as_str()).unwrap_or_else(|e| {
eprintln!("Error: failed to get: {}", e);
std::process::exit(1);
});
}
fn get_json_response(url: &str) -> Result<Value, Box<dyn Error>> {
let resp = ureq::get(url)
.set("Authorization", format!("Bearer {}", API_TOKEN).as_str())
.call()?
.into_json()?;
Ok(resp)
}
This works well. However, if I have multiple calls to get_json_response(), it gets messy to include that same closure over and over.
My solutions is to change it to:
use serde_json::Value;
use std::error::Error;
use ureq;
fn main() {
let json =
get_json_response(format!("{}{}", BASE_URL, LOGIN_URL).as_str()).unwrap_or_else(fail);
}
fn fail(err: Box<dyn Error>) -> ! {
eprintln!("Error: failed to get: {}", err);
std::process::exit(1);
}
This doesn't work because unwrap_or_else() expects a Value to be returned rather than nothing !. I can cheat and change the return value of fail() to -> Value and add Value::Null after the exit(1). It works but feels wrong (and complains).
I could also do unwrap_or_else(|e| fail(e)) which isn't terrible.
Is there an idiomatic way to handle this?