I want to handle error in Retrofit 2.0
Got e.g. code=404
and body=null
, but errorBody()
contains data in ErrorModel
(Boolean status
and String info
).
This is errorBody().content
: [text=\n{"status":false,"info":"Provided email doesn't exist."}]
.
How can I get this data?
Thank for helping me!
This is my code for Retrofit request:
ResetPasswordApi.Factory.getInstance().resetPassword(loginEditText.getText().toString())
.enqueue(new Callback<StatusInfoModel>() {
@Override
public void onResponse(Call<StatusInfoModel> call, Response<StatusInfoModel> response) {
if (response.isSuccessful()) {
showToast(getApplicationContext(), getString(R.string.new_password_sent));
} else {
showToast(getApplicationContext(), getString(R.string.email_not_exist));
}
}
@Override
public void onFailure(Call<StatusInfoModel> call, Throwable t) {
showToast(getApplicationContext(), "Something went wrong...");
}
});
If you want to get data when error response comes (typically a response code except 200) you can do it like that in your onResponse()
method:
if (response.code() == 404) {
Gson gson = new GsonBuilder().create();
YourErrorPojo pojo = new YourErrorPojo();
try {
pojo = gson.fromJson(response.errorBody().string(), YourErrorPojo.class);
Toast.makeText(context, pojo.getInfo(), Toast.LENGTH_LONG).show();
} catch (IOException e) { // handle failure at error parse }
}
When generating YourErrorPojo.class
do following steps :
Go to Json Schema 2 Pojo
Paste your example Json
, and select source type Json , annotation Gson
Your example Json
is : {"status":false,"info":"Provided email doesn't exist."}
- Click Preview and it will generate your
Pojo
class for you.
Add this to your build.gradle
: compile 'com.google.code.gson:gson:2.7'
I used Gson
in this solution but you can get your Json
string using: response.errorBody().string()
Retrofit doesn't see 404 as a failure, so it will enter the onSuccess.
response.isSuccessful()
is true if the response code is in the range of 200-300, so it will enter the else there.
if (response.isSuccessful()) {
showToast(getApplicationContext(), getString(R.string.new_password_sent));
} else {
// A 404 will go here
showToast(getApplicationContext(), getString(R.string.email_not_exist));
}
However since your response was not successful, you do not get the response body with .body()
, but with errorBody()
, errorBody will filled when the request was a success, but response.isSuccessful()
returns false (so in case of a status code that is not 200-300).
I'm using this library Retrobomb, you don't have to serialize at that level.
it's easy to use and customize. It supports annotation for each error type or error code.
If you prefer you can unwrap all errors and handle by your self.
@ErrorMapping(code = 401, errorType = Unauthorized.class)
@PATCH("/v1/widgets/{id}")
Single<Widget> updateWidget(@Path("id") String id, @Body Widget widget);
If you want to get data when error response comes (typically a response code except 200) you can do it like that in your onResponse()
method:
override fun onResponse(call: Call<LoginData>?, response: Response<LoginData>?) {
if (response != null) {
if (response.code() == 200 && response.body() != null) {
val loginData = response.body()
if (loginData != null) {
//Handle success case...
}
} else if (response.code() == 401) {
val converter = ApiClient.getClient()?.responseBodyConverter<ErrorResponseData>(
ErrorResponseData::class.java,
arrayOfNulls<Annotation>(0))
var errorResponse: ErrorResponseData? = null
errorResponse = converter?.convert(response.errorBody())
if (errorResponse != null) {
//Handle Error case..
}
}
}
}