How to properly manage error?

Hello everyone,

I am really confused with a feature I'm trying to implement, let's say I have a Vec<Object> which I am trying to serialize, then trying to send a POST request with the serialized body.

It would look like this :

vec.into_iter()
    .map(|object| serde_json::to_string(&object) )
    .map(|str_object| client.post().body(str_object).send().await )

The first map will return a Result<String, serde_error::Error> while the second map will return a Result<String, reqwest::Error>

So that would obviously not compile, as the documentation says :

Maps a Result<T, E> to Result<U, E>

What is an idomatic way to manage error properly in a functional fashion ? do I have to create my own error type to wrap those error in each map ?

The docs of map you mentioned are from Result's map: Result in core::result - Rust
But the map you're calling is Iterator's map: Iterator in std::iter - Rust

The code you posted wouldn't compile, but for different reasons. The first map maps each Object into a Result<String, serde_error::Error> as you say. The second map then maps each Result<String, serde_error::Error>, which you then try to give to client.post().body(str_object), but you can't pass any Result to .body(), no matter what the Error type. You also can't .await inside a non-async closure.

There are ways to handle errors and async when using iterator combinators, but in this case the idiomatic way is to keep it simple with a for loop:

for object in vec {  
    let str_object = serde_json::to_string(&object)?;
    client.post().body(str_object).send().await?;
}

You can do that, and that's typically the approach taken by library code. See thiserror - Rust to make it more convenient.

You can also use a general error type that allow you to convert most other errors into them. Box<dyn Error>, anyhow::Error or eyre::Error are some such types. For example

async fn send_objects() -> Result<(), anyhow::Error> {
    let client = get_client_from_somewhere();
    let objects = get_vec_of_objects_from_somewhere();

    for object in objects {
        let str_object = serde_json::to_string(&object)?;
        client.post().body(str_object).send().await?;
    }
    Ok(())
}
2 Likes

Sorry for the piece of code i've given, I tried to make it simple, but I introduced lots of mistake.

Thank you, this is an amazing answer. I wasn't aware of many things you told me.