How to handle error response with Retrofit 2 using synchronous request?
I need process response that in normal case return pets array and if request has bad parametrs return error json object. How can I process this two situations?
I am trying to use this tutorial but the main problem is mapping normal and error json to objects.
My normal response example:
[ {
"type" : "cat",
"color": "black"
},
{
"type" : "cat",
"color": "white"
} ]
Error response example:
{"error" = "-1", error_description = "Low version"}
What I got:
Call<List<Pet>> call = getApiService().getPet(1);
Response<List<Pet>> response;
List<Pet> result = null;
try {
response = call.execute(); //line with exception "Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path"
if(!response.isSuccessful()){
Error error = parseError(response);
Log.d("error message", error.getErrorDescription());
}
if (response.code() == 200) {
result = response.body();
}
} catch (IOException e) {
e.printStackTrace();
}
Retrofit 2 has a different concept of handling "successful" requests than Retrofit 1. In Retrofit 2, all requests that can be executed (sent to the API) and for which you’re receiving a response are seen as "successful". That means, for these requests, the onResponse callback is fired and you need to manually check whether the request is actually successful (status 200-299) or erroneous (status 400-599).
If the request finished successfully, we can use the response object and do whatever we wanted. In case the error actually failed (remember, status 400-599), we want to show the user appropriate information about the issue.
For more details refer this link
After going through a number of solutions. Am posting it for more dynamic use. Hope this will help you guys.
My Error Response
{
"severity": 0,
"errorMessage": "Incorrect Credentials (Login ID or Passowrd)"
}
Below is as usual call method
private void makeLoginCall() {
loginCall = RetrofitSingleton.getAPI().sendLogin(loginjsonObject);
loginCall.enqueue(new Callback<Login>() {
@Override
public void onResponse(Call<Login> call, Response<Login> response) {
if (response != null && response.code() == 200){
//Success handling
}
else if (!response.isSuccessful()){
mServerResponseCode = response.code();
Util.Logd("In catch of login else " + response.message());
/*
* Below line send respnse to Util class which return a specific error string
* this error string is then sent back to main activity(Class responsible for fundtionality)
* */
mServerMessage = Util.parseError(response) ;
mLoginWebMutableData.postValue(null);
loginCall = null;
}
}
@Override
public void onFailure(Call<Login> call, Throwable t) {
Util.Logd("In catch of login " + t.getMessage());
mLoginWebMutableData.postValue(null);
mServerMessage = t.getMessage();
loginCall = null;
}
});
}
Below Is util class to handle parsing
public static String parseError(Response<?> response){
String errorMsg = null;
try {
JSONObject jObjError = new JSONObject(response.errorBody().string());
errorMsg = jObjError.getString("errorMessage");
Util.Logd(jObjError.getString("errorMessage"));
return errorMsg ;
} catch (Exception e) {
Util.Logd(e.getMessage());
}
return errorMsg;
}
Below in viewModel observer
private void observeLogin() {
loginViewModel.getmLoginVModelMutableData().observe(this, login -> {
if (loginViewModel.getSerResponseCode() != null) {
if (loginViewModel.getSerResponseCode().equals(Constants.OK)) {
if (login != null) {
//Your logic here
}
}
//getting parsed response message from client to handling class
else {
Util.stopProgress(this);
Snackbar snackbar = Snackbar.make(view, loginViewModel.getmServerVModelMessage(), BaseTransientBottomBar.LENGTH_INDEFINITE).setAction(android.R.string.ok, v -> { });
snackbar.show();
}
} else {
Util.stopProgress(this);
Snackbar snackbar = Snackbar.make(view, "Some Unknown Error occured", BaseTransientBottomBar.LENGTH_INDEFINITE).setAction(android.R.string.ok, v -> { });
snackbar.show();
}
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With