Reputation: 3899
I have simple function login request to server, in this function i have some error handling .
try {
final response = await http.post(
'${appConfig.baseApiUrl}/${appConfig.userController}/loginUser',
headers: appConfig.headersApi,
body: {
"username": username,
"password": password,
},
);
final Map<String, dynamic> responseJson = json.decode(response.body);
if (responseJson["status"] == "ok") {
List userList = responseJson['data'];
List<UserModel> result = userList.map((e) => UserModel.fromJson(e)).toList();
return result;
} else {
throw CustomError(responseJson['message']);
}
} on SocketException catch (_) {
return Future.error(ConstText.NO_CONNECTION);
} on TimeoutException catch (_) {
return Future.error(ConstText.TIMEOUT_EXCEPTION);
} on FormatException catch (_) {
return Future.error(ConstText.FORMAT_EXCEPTION);
} catch (e) {
return Future.error(e.toString());
}
}
In above source code, I have 4 Handling error like SocketException,TimeoutException,FormatException and UnknownException. This function work fine, but if i create another function for request server i should repeat the error handling again. My question is , it's possible to make error handling reusable ? I want something like this.
requestServer(yourRequestServer) async{
try{
return yourRequestServer;
}on SocketException catch (_) {
return Future.error(ConstText.NO_CONNECTION);
} on TimeoutException catch (_) {
return Future.error(ConstText.TIMEOUT_EXCEPTION);
} on FormatException catch (_) {
return Future.error(ConstText.FORMAT_EXCEPTION);
} catch (e) {
return Future.error(e.toString());
}
}
Future<String> testLogin(String username,String password)async{
requestServer({
final response = await http.post(
'${appConfig.baseApiUrl}/${appConfig.userController}/loginUser',
headers: appConfig.headersApi,
body: {
"username": username,
"password": password,
},
);
final Map<String, dynamic> responseJson = json.decode(response.body);
if (responseJson["status"] == "ok") {
List userList = responseJson['data'];
List<UserModel> result = userList.map((e) => UserModel.fromJson(e)).toList();
return result;
} else {
throw CustomError(responseJson['message']);
}
});
}
Or if you have another suggestion , i really appreciate that. Thank's.
Upvotes: 1
Views: 1725
Reputation: 71633
Reusing code is always a matter of figuring out what to keep an what to abstract away.
In your case, you want to reuse the catch
clauses.
The thing you are abstracting over is the body of the try
clause, which appears to contain some asynchronous code.
Since you are abstracting over code, you'll need to pass in a function. That's the only way to make code into an argument value.
So you'll need something like:
Future<T> requestServer(FutureOr<T> computation()) {
try {
return await computation();
} on SocketException catch (_) {
throw ConstText.NO_CONNECTION;
} on TimeoutException catch (_) {
throw ConstText.TIMEOUT_EXCEPTION;
} on FormatException catch (_) {
throw ConstText.FORMAT_EXCEPTION;
} catch (e) {
throw e.toString();
}
}
You can then use it as:
var result = await requestServer(() {
final response = await http.post(...
...
return result;
...
});
I changed the return Future.error(someString);
to throw someString
because it's the same thing, and the latter is much more readable. You are throwing strings here, not exception or error objects. That's a bold move, but as long as you are the one to catch them again, it's reasonable. It's not a good API for other people to have to catch.
Upvotes: 3