I am using the Retrofit library to do REST calls to a service I am using.
If I make an API call to my service and have a failure, the service returns a bit of JSON
So after a little more hunting I found the answer.
Here's my failure callback:
@Override public void failure(RetrofitError retrofitError) {
String serverError = null;
try {
serverError = extractServerError(retrofitError.getResponse().getBody().in());
} catch (Exception e) {
Log.e("LOG_TAG", "Error converting RetrofitError server JSON", e);
}
if (serverError!=null) {
Log.i(LOG_TAG, serverError);
}
Intent intent = new Intent(ACTION_REGISTRATION_ERROR);
intent.putExtra("ServerError", serverError);
LocalBroadcastManager.getInstance(FamDooApplication.CONTEXT).sendBroadcastSync(intent);
}
And here's the method that is called to extract the server error:
public static String extractServerError(java.io.InputStream is) {
String serverError = null;
String serverErrorDescription = null;
try {
String s = convertStreamToString(is);
JSONObject messageObject = new JSONObject(s);
serverError = messageObject.optString("error");
serverErrorDescription = messageObject.optString("error_description");
if (serverErrorDescription!=null && !serverErrorDescription.equals("")) {
return serverErrorDescription;
} else {
return serverError;
}
//String serverStack = messageObject.getString("stack");
} catch (Exception e) {
Log.e("Basemodel", "Error converting RetrofitError server JSON", e);
}
return "";
}
This will extract the error information sent by the service that is encoded in the JSON.
I compile many answer and wrote some code to achieve something nicer :
{
"errors": {
"email": [
"Email not valid.",
"Unable to find the user toto@toto.fr."
]
}
}
I take all item in 'email' and display them concatained with Guava Joiner:
String json = new String(((TypedByteArray)error.getResponse()
.getBody()).getBytes());
Map<String, Object> map = new Gson().fromJson(
json, new TypeToken<Map<String, Map<String, List<String>>>>() {}.getType());
try {
List<String> errorsEmail =
(List<String>) ((Map)map.get("errors")).get("email");
Toast.makeText(getApplicationContext(), Joiner.on("\n")
.join(errorsEmail), Toast.LENGTH_SHORT).show();
} catch(Exception e){
Log.e(Constants.TAG, e.getMessage());
}
A much neater way to do this is to create a class that can do the parsing/conversion for you, one that you can call anytime, anywhere.
public class ApiError {
public String error = "An error occurred";
public ApiError(Throwable error) {
if (error instanceof HttpException) {
String errorJsonString = null;
try {
errorJsonString = ((HttpException)
error).response().errorBody().string();
} catch (IOException e) {
e.printStackTrace();
}
JsonElement parsedString = new
JsonParser().parse(errorJsonString);
this.error = parsedString.getAsJsonObject()
.get("error")
.getAsString();
} else {
this.error = error.getMessage() != null ? error.getMessage() : this.error;
}
}
}
You can now use this anywhere, like so
ApiError error = new ApiError(error)
error.error
This is all from this blog post (which I wrote).