Help with pipeline of Results

I'm not sure how to idiomatically handle the following expressions that return Results. This is in a main function which is parsing comand-line args, so this is the end of the line so to speak. I don't want to propagate errors but rather handle them here. The first match statement is fine. Within the Ok arm of the match, the two functions that return Results will rarely fail so I don't want the verbosity of nested matches.

...
// normalized _path is defined above but left out for brevity...
// server.request is a an associated struct method defined elsewhere as well.
match server.request(&method.to_string(), normalized_path) {
    Ok(response) => {
        let json: ureq::serde_json::Value = response.into_json().unwrap();
        println!("{}", to_string_pretty(&json).unwrap());
    },
    Err(err) => {
       // print error to stderr and exit. The error is probably due to a non-ok HTTP response.

How do I concisely handle the two unwraps, exiting non-zero but with a useful error message? The first panic could happen because of some IO error, the second could happen because of malformed JSON. I don't want more nested matches. Do I want to use and_then since, the first unwrapped value is fed into the next function?

All problems in computing can be solved by adding another layer of indirection:

use std::process::ExitCode;

fn run() -> anyhow::Result<()> {
    let response = server.request(&method.to_string(), normalized_path)?;
    let json: ureq::serde_json::Value = response.into_json()?;
    println!("{}", to_string_pretty(&json)?);
    Ok(())
}

fn main() -> ExitCode {
    if let Err(error) = run() {
        eprintln!("Error: {}", error);
        ExitCode::FAILURE
    } else {
        ExitCode::SUCCESS
    }
}
3 Likes

So it seems the anyhow crate provides a trait object? From the book this is a reference to a trait? Kind of confused about that. And this allows to generalize errors. If I weren't using anyhow I'd handle both errors and manually create a wrapper error and assign the return type of the function to that general error type. Is that right?

is anyhow used very often by rust devs? Are there downsides performance or otherwise?

Well the anyhow crate is a red herring; I just used that to make the code compile easily. The point I was trying to make is that you would indeed use ?-bubbling anyway, because that makes error handling concise, and then you would only need to match only once in main.

2 Likes