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?