What's the best practice to throw an Exception in Flutter - flutter

I have an exception that gets thrown multiple times before getting handled in my code, (the same error object gets thrown 4 times in the tree).
During each throw , flutter appends the word Exception: to my error object, so the final shape of the message is:
Exception: Exception: Exception: Exception: SocketException: OS Error: Connection refused, errno = 111, address = 10.12.7.15, port = 39682
And this is an example of how I handle exceptions:
getSomeData () async {
try {
await myFunction3();
} catch (e) {
throw Exception(e);
}
}
/*****************************************/
Future<void> myFunction3 () async {
try {
await myFunction2();
} catch (e) {
throw Exception(e);
}
}
/*****************************************/
Future<void> myFunction2 () async {
try {
await myFunction1();
} catch (e) {
throw Exception(e);
}
}
/*****************************************/
Future<void> myFunction1() async {
try {
await dio.get(/*some parameters*/);
}
on DioError catch (e) {
throw Exception(e.error);
}
catch (e) {
throw Exception(e);
}
}
I want to throw the Exception() in a right way so the repetition of word Exception: doesn't appear anymore in my error string.

Instead of throwing a new exception, you could rethrow the catched one:
Future<void> myFunction1() async {
try {
await dio.get(/*some parameters*/);
}
on DioError catch (e) {
// do something
rethrow;
}
catch (e) {
// do something
rethrow;
}
}
See more: https://dart.dev/guides/language/effective-dart/usage#do-use-rethrow-to-rethrow-a-caught-exception

Related

Flutter: How do I avoid repetition of try-catch-exception?

This is the code I want to avoid repeating. If possible also try block.
try {
//
} on TimeoutException catch (e) {
log('Timeout Error: $e');
rethrow;
} on SocketException catch (e) {
log('Socket Error: $e');
rethrow;
} on Error catch (e) {
log('General Error: $e');
rethrow;
} catch (e) {
log('All other Errors: $e');
rethrow;
}
You could define a function like:
void tryCatch(Function f) {
try {
f();
} on TimeoutException catch (e) {
log('Timeout Error: $e');
rethrow;
} on SocketException catch (e) {
log('Socket Error: $e');
rethrow;
} on Error catch (e) {
log('General Error: $e');
rethrow;
} catch (e) {
log('All other Errors: $e');
rethrow;
}
}
and then anywhere you want to use it do
tryCatch((){
//your code here
});
One trivial answer could be to refactor that try-catch cascade in a dedicated function or class, in which you return the value if everything's all right, or handle the corresponding error.
I guess yours is just an example code, but if you're just interested in logging an error and then rethrow, you don't need to distinguish between those exceptions and errors.
You can easily retrieve your error's type like so:
try {
// some risky code
} catch(error, stackTrace) {
print(error.runtimeType);
print(error); // calls its internal toString() method
rethrow;
}
Even the above example could be refactored in a dedicated function or class, by the way.
If you're looking into something even more specific let me know, because I'm kinda curious about this, too.

How to stop dio get when the internet is off?

the request is just waiting and not resulting an error, i want an error to be produced when there is no internet but it's just waiting forever
i tried
sendTimeout: 600000,
receiveTimeout: 600000,
but same result
vscode screenshot
You need to wrap your logic inside try/catch block.
try {
var response = await _dio.getUri(
Uri.parse(uri));
if (response.statusCode == 200) {
return response.data;
} else {
throw response;
}
} on SocketException catch (e) {
throw SocketException(e.toString());
} on FormatException catch (_) {
throw FormatException("Unable to process the data");
} catch (e) {
throw e;
}

Flutter custom exception not throwing

I upgraded Flutter from version 2.0.2 to version 2.2.2 and now the custom exceptions that are thrown from a Future function are not being catch.
For example, I got this Future function, where I call another Future that does a server request and returns back the response or throws a custom exception (ApiException) in case of error:
static Future<bool> signUpCustomerRequest(Map<String, dynamic> params) async {
try {
// Here we call this Future function that will do a request to server API.
dynamic _response = await _provider.signUpCustomer(params);
if (_response != null) {
updateUserData(_response);
return true;
}
return false;
} on ApiException catch(ae) {
// This custom exception is not being catch
ae.printDetails();
rethrow;
} catch(e) {
// This catch is working and the print below shows that e is Instance of 'ApiException'
print("ERROR signUpCustomerRequest: $e");
rethrow;
} finally {
}
}
And this is the Future function that does the request to server and throws the ApiException:
Future<User?> signUpCustomer(Map<String, dynamic> params) async {
// POST request to server
var _response = await _requestPOST(
needsAuth: false,
path: routes["signup_client"],
formData: params,
);
// Here we check the response...
var _rc = _response["rc"];
switch(_rc) {
case 0:
if (_response["data"] != null) {
User user = User.fromJson(_response["data"]["user"]);
return user;
}
return null;
default:
print("here default: $_rc");
// And here we have the throw of the custom exception (ApiException)
throw ApiException(getRCMessage(_rc), _rc);
}
}
Before upgrading to Flutter 2.2.2 the catch of custom exceptions worked perfectly. Did something change on this Flutter version? Am I doing something wrong?
Thanks!
I was able to reproduce your bug with the following code:
class ApiException implements Exception {
void printDetails() {
print("ApiException was caught");
}
}
Future<void> doSomething() async {
await Future.delayed(Duration(seconds: 1));
throw ApiException();
}
void main() async {
try {
await doSomething();
} on ApiException catch (ae) {
ae.printDetails();
} catch (e) {
print("Uncaught error: $e"); // This line is printed
}
}
There's an open issue on the dart sdk, which I think might be related, though I'm not sure: https://github.com/dart-lang/sdk/issues/45952.
In any case, I was able to correct the error by returning a Future.error, instead of throwing the error directly:
class ApiException implements Exception {
void printDetails() {
print("ApiException was caught"); // This line is printed
}
}
Future<void> doSomething() async {
await Future.delayed(Duration(seconds: 1));
return Future.error(ApiException());
}
void main() async {
try {
await doSomething();
} on ApiException catch (ae) {
ae.printDetails();
} catch (e) {
print("Uncaught error: $e");
}
}

Flutter & Dart Error Handling Middleware Concept

I check my errors between try blocks. How can I get rid of code repetition by creating an intermediate layer instead of rewriting it within each method?
As seen in the codes, I use try blocks in all operations.
Future<List<Post>> getAll(){
try {
//http get code
}on SocketException {
throw Failure('Message');
}on HttpException {
throw Failure("Http Exception Message");
}on FormatException {
throw Failure("Format Message");
}
}
Future<Post> getPost(){
try {
//http get code
}on SocketException {
throw Failure('Message');
}on HttpException {
throw Failure("Http Exception Message");
}on FormatException {
throw Failure("Format Message");
}
}

How to catch http.get (SocketException)

I'm new to Flutter & Dart, trying to complete my first app.
I can't catch (with try-catch block) http.get SocketException (which happens when you call API and WiFi turned off)
I tried everything on the internet without luck, I even tried (Dio) package to catch this exception, but no success.
How to reproduce: use bottom code...turn off phone's WiFi...call API...now the app crashes with (SocketException) in your IDE.
Image: https://imgur.com/bA0rKEN
here is my simple code (updated)
RaisedButton(
child: Text("Call API"),
onPressed: () async {
try {
http.Response response = await getLoginResponse();
//do something with response
print(response.body);
} catch (e) {
print("Button onPressed Error: " + e.toString());
}
},
)
//---------------------------------------------------------------
Future<http.Response> getLoginResponse() {
return http.get(loginUrl).timeout(Duration(seconds: 10))
.then((response) {
return response;
}, onError: (e) {
print("onError: " + e.toString());
}).catchError((err) {
print("catchError: " + err.toString());
return null;
});
}
You can catch several types of errors and handle each one separately
Example:
import 'dart:io' as Io;
http.Client client = http.Client();
try {
response = await client.get(url).timeout(new Duration(seconds: 10));
} on Io.SocketException catch (_) {
throw Exception('Not connected. Failed to load data');
} on TimeoutException catch (_) {
throw Exception('Not connected. TimeOut Exception');
} catch (e) {
// Default error handling;
}
if you want to get catch in RaisedButton's try-catch block, instead of return null in getLoginInfo() methods, you must return an Exception like this:
Future<List<LoginObject>> getLoginInfo() async {
try {
List<LoginObject> loginObjectList = List<LoginObject>();
http.Response loginResponse =
await http.get(loginUrl).timeout(Duration(seconds: 10));
if (loginResponse.statusCode == 200) {
loginObjectList = loginObjectFromJson(loginResponse.body);
return loginObjectList;
} else {
throw Exception('Authentication Error');
}
} catch (e) {
print("Error: " + e.toString());
return throw Exception('Connection Error');;
}
}
Note: If you want to handle each one of error response, you can create an custom ErrorModelClass and handle error state with it and finally return your ErrorModelClass.
catch (error) {
print(error);
throw error is HttpResponseError ? error : HttpResponseError(0,"error connection");
HttpResponseError is my custom model class.