Flutter can't catch exception after throw exception - flutter

I have func , after call function, I want to throw an ApiException, but I'nt catch it.
Step 1:
I'nt catch ApiException here
FutureOr<void> login({String? user, String? password}) async {
try {
emit(LoadingLoginState());
await loginUseCase?.login(user, password);
} on ApiException catch (e) { // I'nt catch ApiException here
emit(ErrorLoginState(errorMessage: e.errorMessage));
} catch (_) {
emit(ErrorLoginState(errorMessage: S.current.connectionProblem));
}
}
Step 2:
class LoginUseCase {
final LoginRepository _loginRepository;
LoginUseCase(this._loginRepository);
Future<LoginResponse?>? login(String? user, String? password) =>
_loginRepository.login(user, password);
}
Step 3:
abstract class LoginRepository{
Future<LoginResponse?>? login(String? user, String? password);
}
Step 4:
throw ApiException()
class UserRepoImpl implements LoginRepository {
UserApi? userApi;
UserRepoImpl({this.userApi});
#override
Future<LoginResponse?>? login(String? user, String? password) async {
throw ApiException();
}
}

To capture errors asynchroniously, you could use .catchError
callApi().catchError((error){
// handle exception here
});
Upd: your code
FutureOr<void> login({String? user, String? password}) async {
emit(LoadingLoginState());
await loginUseCase?.login(user, password)
?.catchError(error) {
if(error is ApiException) {
emit(ErrorLoginState(errorMessage: e.errorMessage));
} else {
emit(ErrorLoginState(errorMessage: S.current.connectionProblem));
}
}
}

Try wrapping the concrete implementation with a try-catch block like this:
class LoginUseCase {
final LoginRepository _loginRepository;
LoginUseCase(this._loginRepository);
Future<LoginResponse?>? login(String? user, String? password) {
try{
_loginRepository.login(user, password);
} on ApiException catch(e){
print('API Exception caught');
}
}
}

Related

Catch block not called in async future flutter

Why is my catch block not called in this code when there is exception
Future registerWithCredentials() async {
if(state.status == RegisterStatus.loading) return;
emit(state.copyWith(status: RegisterStatus.loading));
try{
await _authRepository.register(email: state.email, password: state.password);
emit(state.copyWith(status: RegisterStatus.success));
}catch (e) {
//catch errors
debugPrint('except: "there is an error"');
emit(state.copyWith(status: RegisterStatus.error));
}
}
I have also tried like this:
try {
await _authRepository.register(email: state.email, password: state.password);
emit(state.copyWith(status: RegisterStatus.success));
} on FirebaseAuthException catch (e) {
debugPrint('except: "there is an error"');
emit(state.copyWith(status: RegisterStatus.error));
}
Repository -> register
Future<void> register({
required String email,
required String password,
}) async {
try {
await _firebaseAuth.createUserWithEmailAndPassword(email: email,
password: password);
} catch(_) {
//the catch here works but I need to send the error to cubit above and
also send to UI... how to do that
}
}
This what I want to do -> Send the error from repository to cubit to ui and display in widget/ui
If you catch the exception in the repository, then you have "used" (handled) the exception. If you want to catch the same exception in the bloc, you'll have to rethrow it. So, either re-throw the exception, or remove the try catch in the repository.

"on HttpException catch (error)" desn't work in flutter

I made this code to handle error from the server Firebase with flutter :
This is the main function :
try {
if (_authMode == AuthMode.Login) {
print("log in");
await Provider.of<Auth>(context, listen: false)
.signIn(_authData['email'], _authData['password']);
} else {
await Provider.of<Auth>(context, listen: false)
.signUp(_authData['email'], _authData['password']);
}
} on HttpException catch (error) {
print("Check error");
if (error.toString().contains("EMAIL_EXISTS")) {
_ServerError =
"The email address is already in use by another account.";
}
if (error.toString().contains("TOO_MANY_ATTEMPTS_TRY_LATER")) {
_ServerError =
"We have blocked all requests from this device due to unusual activity.\n Try again later.";
} else {
_ServerError = "Something wrong. \n Try again later!";
}
} catch (error) {
print(error.toString() );
}
This is the called function :
Future<void> signIn(String? email, String? password) async {
const _url =
"https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=APICODE";
_authentication(_url, email, password);}
Future<void> _authentication(
String _url, String? email, String? password) async {
try {
final _response = await http.post(Uri.parse(_url),
body: json.encode({
'email': email,
'password': password,
'returnSecureToken': true
}));
final _responseData = json.decode(_response.body);
if (_responseData['error'] != null) {
throw HttpException(_responseData['error']['message']);
}
} catch (error) {
throw error;
}}
But the problem is when the called function throw the HttpException error, I don't get it in the main function because the Catch doesn't work because I don't get the message "check error" in the panel ?!
this is the panel :
Can you help me please ?
The problem is I forgot to add return to called function :
Future<void> signIn(String? email, String? password) async {
const _url =
"https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=APICODE";
return _authentication(_url, email, password);
}

A value of type 'Stream<User?>' can't be returned from the function 'user' because it has a return type of 'Stream<User>?'

I am getting red line on auth.authStateChanges(),
Error says : A value of type 'Stream<User?>' can't be returned from the function 'user' because it has a return type of 'Stream?'.
class Auth {
final FirebaseAuth auth;
Auth({required this.auth});
Stream<User>? get user => auth.authStateChanges(); <-- here
Update now i get this error:
Future<String?> createAccount({required String email, required String password}) async {
try {
await auth.createUserWithEmailAndPassword( <-- here **auth**
email: email.trim(),
password: password.trim(),
);
return "Success";
} on FirebaseAuthException catch (e) {
return e.message;
} catch (e) {
rethrow;
}
}
Here is your updated class
import 'package:firebase_auth/firebase_auth.dart';
class Auth {
final FirebaseAuth auth;
Auth({required this.auth});
Stream<User?> get user => auth.authStateChanges();
Future<String?> createAccount({required String email, required String password}) async {
try {
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: email.trim(),
password: password.trim(),
);
return "Success";
} on FirebaseAuthException catch (e) {
return e.message;
} catch (e) {
rethrow;
}
}
}

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