How do I return error from a Future in dart?
FlutterDartFutureFlutter Problem Overview
In my flutter app, I have a future that handles http requests and returns the decoded data. But I want to be able to send an error if the status code != 200
that can be gotten with the .catchError()
handler.
Heres the future:
Future<List> getEvents(String customerID) async {
var response = await http.get(
Uri.encodeFull(...)
);
if (response.statusCode == 200){
return jsonDecode(response.body);
}else{
// I want to return error here
}
}
and when I call this function, I want to be able to get the error like:
getEvents(customerID)
.then(
...
).catchError(
(error) => print(error)
);
Flutter Solutions
Solution 1 - Flutter
Throwing an error/exception:
You can use either return
or throw
to throw an error or an exception.
-
Usingreturn
:Future<void> foo() async { if (someCondition) { return Future.error('FooError'); } }
-
Usingthrow
:Future<void> bar() async { if (someCondition) { throw Exception('BarException'); } }
Catching the error/exception:
You can use either catchError
or try-catch
block to catch the error or the exception.
-
UsingcatchError
:foo().catchError(print);
-
Usingtry-catch
:try { await bar(); } catch (e) { print(e); }
Solution 2 - Flutter
You can use throw
:
Future<List> getEvents(String customerID) async {
var response = await http.get(
Uri.encodeFull(...)
);
if (response.statusCode == 200){
return jsonDecode(response.body);
}else{
// I want to return error here
throw("some arbitrary error"); // error thrown
}
}
Solution 3 - Flutter
//POST
Future<String> post_firebase_async({String? path , required Product product}) async {
final Uri _url = path == null ? currentUrl: Uri.https(_baseUrl, '/$path');
print('Sending a POST request at $_url');
final response = await http.post(_url, body: jsonEncode(product.toJson()));
if(response.statusCode == 200){
final result = jsonDecode(response.body) as Map<String,dynamic>;
return result['name'];
}
else{
//throw HttpException(message: 'Failed with ${response.statusCode}');
return Future.error("This is the error", StackTrace.fromString("This is its trace"));
}
}
Here is how to call:
final result = await _firebase.post_firebase_async(product: dummyProduct).
catchError((err){
print('huhu $err');
});
Solution 4 - Flutter
If whenComplete()
’s callback throws an error, then whenComplete()
’s Future completes with that error:
void main() {
funcThatThrows()
// Future completes with a value:
.catchError(handleError)
// Future completes with an error:
.whenComplete(() => throw Exception('New error'))
// Error is handled:
.catchError(handleError);
}
Solution 5 - Flutter
Another way to solve this is by using the dartz package.
An example of how to use it would look something similar like this
import 'package:dartz/dartz.dart';
abstract class Failure {}
class ServerFailure extends Failure {}
class ResultFailure extends Failure {
final int statusCode;
const ResultFailure({required this.statusCode});
}
FutureOr<Either<Failure, List>> getEvents(String customerID) async {
try {
final response = await http.get(
Uri.encodeFull(...)
);
if (response.statusCode == 200) {
return Right(jsonDecode(response.body));
} else {
return Left(ResultFailure(statusCode: response.statusCode));
}
}
catch (e) {
return Left(ServerFailure());
}
}
main() async {
final result = await getEvents('customerId');
result.fold(
(l) => print('Some failure occurred'),
(r) => print('Success')
);
}