[RESOLVED] Error handling with Futures


#1

I am writing a library to access an HTTP API asynchronous using hyper and Futures.
There is this one thing that I just can’t wrap my head around: How to deal with errors before even starting the request / spawning the Future.

Here is an example of how I am writing the client implementation:

pub fn get(self) -> impl Future<Item = Component, Error = Error> {
    let result = doing_some_checks();
    if result.is_error() {
        // The following obviously won't work:
        return Err(Error::SomeErrorKind);
    }

    // safe to use
    let something = result.unwrap();
    let request = ... // creating hyper request

    self.client
        .request(request) // returns a Future
        .and_then(|response| {
            // doing stuff with the response ...
            Ok(Component)
        })
}

Is there any way to deal with errors before doing the HTTP request? It will have to do with returning some kind of an ‘error’ Future, but I could not find a working solution so far, a simple return futures::future::err(Error::ErrorKind) won’t work.


#2

Call this function: https://docs.rs/futures/0.2.1/futures/future/fn.err.html

fn get(self) -> Box<dyn Future<Item = Component, Error = Error>> {
    ...
    if let Err(e) = result {
        return Box::new(futures::future::err(somehow_convert_error_type(e)));
    }
}

The important thing is using a Boxed trait object in comparison to impl Trait.
You can not return two different types in two control flow paths from one impl Trait returning function.


#3

Edit:
You might want to read this: https://github.com/rust-lang/rfcs/blob/master/text/2113-dyn-trait-syntax.md


#4

Great, that helped a lot! Boxing seems like a good thing to do.
Thank you!


#5

If you didn’t want to box, you could use the futures::future::Either enum to allow two different types. The signature would look like:

fn get(self) -> Either<impl Future<Item=Component, Error=Error>, impl Future<Item=Component, Error=Error>> {...}