Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catch error using catchError in a future and throw another type

I am not sure if this type of error handling and abstraction is done in a wrong way.

Future<void> _refresh() {
  return Future(() => throw someError)
       .catchError((error) {
         // maybe do something here
         throw abstractedError; //or even the same error
      });

Being able in another place to use it accordingly:

// in a widget/another place

void doSomething() { 
   _refresh()
     .then((_) => bla())
     .catchError((error) {
      //showSomeAlert() or handleSomething()
  });
}
like image 499
Durdu Avatar asked Apr 09 '19 15:04

Durdu


2 Answers

Your solution should work (simply throw another exception), but a more expressive way is probably to use Future.error:

Future<void> someApi() {
  return Future(() {
    throw FirstError();
  }).catchError((error, stackTrace) {
    print("inner: $error");
    // although `throw SecondError()` has the same effect.
    return Future.error(SecondError());
  });
}

and then use

  someApi()
    .then((val) { print("success"); })
    .catchError((error, stackTrace) {
      // error is SecondError
      print("outer: $error");
    });

You can play around with it at: https://dartpad.dartlang.org/8fef76c5ba1c76a23042025097ed3e0a

like image 171
Herbert Poul Avatar answered Oct 03 '22 14:10

Herbert Poul


We have in the flutter framework the description for the catch function:

  • Handles errors emitted by this [Future].
    • This is the asynchronous equivalent of a "catch" block. ... Future catchError(Function onError, {bool test(Object error)});

When chaining futures I would advise against of using:

throw error;

and instead use:

return Future.error(SecondError());

This is because if you chain a future and expect to catch the error using the catchError future you will have the following problem.

Future<void> _refresh() {
  return throw Exception("Exception");
}

void main() {
    _refresh() // .then((_) => print("bla"))
    .catchError(() => print("not able to be reached"));
}

And you will get an error Uncaught exception: Exception: Exception.

This is similar when using RX (in general) and instead of throwing you send down the chain a Sigle.error (or any other observable with error).


TLDR:

When working with Futures and chaining them (including catchError) use Future.error(Exception("Exception")) to handle errors.

If you are using throw make sure or surround with try catch or Future(() -> throw ... )

like image 44
Durdu Avatar answered Oct 03 '22 16:10

Durdu