Handling exception HTTP request flutter - flutter

I want to handle http request flutter with some error message but I got so many errors here. I just make it based on the suggestion but it didn't work for me. Please, anyone, help me
Here is my function to call API
getData(data, apiUrl) async {
var tempUrl = _url + apiUrl + await _getToken();
Uri uri = Uri.parse(tempUrl);
var fullUrl = uri.replace(queryParameters: data);
var res;
try {
var response = await http.get(fullUrl, headers: _setHeaders()).timeout(
const Duration(seconds: 60));
print(response.statusCode);
if (response.statusCode != 200) {
res = {
"success": false,
"status": response.statusCode,
"message": _returnResponse(response)
};
}
else {
res = response;
}
}
on SocketException {
throw FetchDataException('No Internet connection');
}
on TimeoutException catch (e) {
res = {
"success": false,
"status": response.statusCode,
"message": "Connection timeout"
};
} on Error catch (e) {
print('Error: $e');
}
return res;
}
This is my return response for the others except 200
dynamic _returnResponse(http.Response response) {
switch (response.statusCode) {
case 400:
throw BadRequestException(response.body.toString());
case 401:
case 403:
throw UnauthorisedException(response.body.toString());
case 500:
default:
throw FetchDataException(
'Error occured while Communication with Server with StatusCode : ${response
.statusCode}');
}
}
and here is my app_exception.dart I got from StackOverflow and other forums
class AppException implements Exception {
final _message;
final _prefix;
AppException([this._message, this._prefix]);
String toString() {
return "$_prefix$_message";
}
}
class FetchDataException extends AppException {
FetchDataException([String message])
: super(message, "Error During Communication: ");
}
class BadRequestException extends AppException {
BadRequestException([message]) : super(message, "Invalid Request: ");
}
class UnauthorisedException extends AppException {
UnauthorisedException([message]) : super(message, "Unauthorised: ");
}
class InvalidInputException extends AppException {
InvalidInputException([String message]) : super(message, "Invalid Input: ");
}
I have tried so many suggestions but it didn't work at all
I got this error
Error: 'SocketException' isn't a type.
on SocketException {
^^^^^^^^^^^^^^^
Error: 'TimeoutException' isn't a type.
on TimeoutException catch (e) {
^^^^^^^^^^^^^^^^

I used dio package. That's more easier and bug-less than i make it
https://pub.dev/packages/dio

If the error occurring is on SocketException and Timeout exception ensure you have imported both dart.io and dart.async respectively in that file. As pertains to you code I was able to successfully run it but you can refer to the answer by Paresh Mangukiya for a step by step or refer here for more clarification on how to handle Network calls and exceptions with custom error responses in flutter.

Related

Error: DioError [DioErrorType.other]: SocketException: Failed host lookup: not being caught

I am using dio 4.0.2. The problem is that when there is no internet connection(when internet and wifi is not turned on), SocketException: Failed host lookup is not being caught. I checked via interceptor's onError method and I am sure it is sending error from interceptor. But post request is not throwing error for this.
Here is my interceptor on error code:
#override
void onError(DioError err, ErrorInterceptorHandler handler) {
super.onError(err, handler);
}
How can I catch this?
I'm using it like this:
bool _isServerDown(DioError error) {
return (error.error is SocketException) || (error.type == DioErrorType.connectTimeout);
}
#override
Future<void> onError(DioError error, ErrorInterceptorHandler handler) async {
if (_isServerDown(error)) {
Response? response;
try {
response = await tryAnotherUrl(error.requestOptions);
} catch (error) {
if (error is DioError) {
response = error.response;
handler.next(error);
return;
}
}
if (response != null) {
handler.resolve(response);
} else {
handler.next(error);
}
return;
}
Not sure why, but this worked for me:
// add error interceptor to catch all errors
dioBuilder.dio.interceptors.add(
InterceptorsWrapper(
onError: (error, handler) {
// Do stuff here
handler.reject(error); // Added this line to let error propagate outside the interceptor
},
),
);

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");
}
}

How to create a screen on socket exception in flutter?

In my flutter project I need to show some illustration images when socket exception occurs when API was called. How can I do that ?
Thanks in advance
This will help on socket exception and format exception.
Create model class for httpresponse
class HTTPResponse<T> {
bool isSuccessful;
T data;
String message;
int responseCode;
HTTPResponse(this.isSuccessful, this.data, {this.message, this.responseCode});
}
Then use this model in api response like this
Future<HTTPResponse<List<Post>>> getPosts(
{int limit = 20, int page = 1}) async {
String url =
'https://jsonplaceholder.typicode.com/posts?_limit=$limit&_page=$page';
Uri uri = Uri.parse(url);
try {
var response = await http.get(uri);
if (response.statusCode == 200) {
var body = json.decode(response.body);
List<Post> postsList = [];
body.forEach((e) {
Post post = Post.fromJson(e);
postsList.add(post);
});
return HTTPResponse(
true,
postsList,
responseCode: response.statusCode,
);
} else {
return HTTPResponse(false, null,
message: 'Invalid response from server',
responseCode: response.statusCode);
}
} on SocketException {
return HTTPResponse(false, [], message: 'Unable to reach the internet');
} on FormatException {
return HTTPResponse(false, [], message: 'Invalid response from server');
} catch (e) {
return HTTPResponse(false, [],
message: "Something went wrong please try in a minute or two");
}
}
It depends on where you want to show it in the widget tree. One simple example would be to push a new screen on to the navigation stack. You will need the BuildContext in your function where the exception might occur.
void someMethod(BuildContext context) {
try {
//some code that might throw an exception
} on Exception catch (_) {
Navigator.pushNamed(context, "Your illustration view");
}
}
Another example would be to add it to your widget tree depending on a bool. You set that bool to true when an exception is thrown.
void someOtherMethod() {
try {
//some code that might throw an exception
} on Exception catch (_) {
setState(() {
hasThrownError = true;
});
}
}
Use it in your widget tree like so:
bool hasThrownError = false;
Widget buildWidgetTree() {
return hasThrownError
? Text("This is where you can show your error illustration")
: Text("This is wher you can show your regular view");
}

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.

How to catch exception in flutter?

This is my exception class. Exception class has been implemented by the abstract exception class of flutter. Am I missing something?
class FetchDataException implements Exception {
final _message;
FetchDataException([this._message]);
String toString() {
if (_message == null) return "Exception";
return "Exception: $_message";
}
}
void loginUser(String email, String password) {
_data
.userLogin(email, password)
.then((user) => _view.onLoginComplete(user))
.catchError((onError) => {
print('error caught');
_view.onLoginError();
});
}
Future < User > userLogin(email, password) async {
Map body = {
'username': email,
'password': password
};
http.Response response = await http.post(apiUrl, body: body);
final responseBody = json.decode(response.body);
final statusCode = response.statusCode;
if (statusCode != HTTP_200_OK || responseBody == null) {
throw new FetchDataException(
"An error occured : [Status Code : $statusCode]");
}
return new User.fromMap(responseBody);
}
CatchError doesn't catch the error when the status is not 200. In short error caught is not printed.
Try
void loginUser(String email, String password) async {
try {
var user = await _data
.userLogin(email, password);
_view.onLoginComplete(user);
});
} on FetchDataException catch(e) {
print('error caught: $e');
_view.onLoginError();
}
}
catchError is sometimes a bit tricky to get right.
With async/await you can use try/catch like with sync code and it is usually much easier to get right.
Let's say this is your function which throws an exception:
Future<void> foo() async {
throw Exception('FooException');
}
You can either use try-catch block or catchError on the Future since both do the same thing.
Using try-catch
try {
await foo();
} on Exception catch (e) {
print(e); // Only catches an exception of type `Exception`.
} catch (e) {
print(e); // Catches all types of `Exception` and `Error`.
}
Use catchError
await foo().catchError(print);
I was trying to find this answer when got to this page, hope it helps: https://stackoverflow.com/a/57736915/12647239
Basicly i was just trying to catch an error message from a method, but i was calling
throw Exception("message")
And in "catchError" i was getting "Exception: message" instead of "message".
catchError(
(error) => print(error)
);
fixed with the return in the above reference
Future < User > userLogin(email, password) async { try {
Map body = {
'username': email,
'password': password
};
http.Response response = await http.post(apiUrl, body: body);
final responseBody = json.decode(response.body);
final statusCode = response.statusCode;
if (statusCode != HTTP_200_OK || responseBody == null) {
throw new FetchDataException(
"An error occured : [Status Code : $statusCode]");
}
return new User.fromMap(responseBody); }
catch (e){
print(e.toString());
}