Obtenir JSON depuis l’object RetrofitError à l’aide de Retrofit

J’utilise la bibliothèque Retrofit pour effectuer des appels REST vers un service que j’utilise.

Si je lance un appel API à mon service et que je suis défaillant, le service renvoie un bit JSON avec les éléments d’erreur HTTP standard. À l’aide de l’object RetrofitError inclus dans le rappel d’échec, je peux trouver le code d’état HTTP et plusieurs autres éléments, mais je ne suis pas en mesure de récupérer le JSON renvoyé par le service.

Par exemple, supposons que j’appelle l’API où j’essaie de créer un utilisateur. Si le nom d’utilisateur existe déjà, le service renverra un code d’erreur 400 avec un JSON comme celui-ci:

 {"error":"Username already in use"} 

Parce qu’un simple code d’erreur 400 n’est pas assez spécifique, j’ai vraiment besoin d’accéder au JSON renvoyé.

Est-ce que quelqu’un sait comment je peux obtenir ces données JSON? J’ai essayé de regarder chaque champ de l’object RetrofitError et je ne le trouve nulle part. Y a-t-il quelque chose de plus à faire?

Vous pouvez utiliser la méthode getBodyAs de l’object RetrofitError . Il convertit la réponse en un object Java de la même manière que les autres conversions Retrofit. Définissez d’abord une classe qui décrit votre réponse d’erreur JSON:

 class RestError { @SerializedName("code") public int code; @SerializedName("error") public Ssortingng errorDetails; } 

Ensuite, utilisez la méthode mentionnée précédemment pour obtenir l’object qui décrit l’erreur plus en détail.

 catch(RetrofitError error) { if (error.getResponse() != null) { RestError body = (RestError) error.getBodyAs(RestError.class); log(body.errorDetails); switch (body.code) { case 101: ... case 102: ... } } } 

Retrofit 2.0 a changé la façon dont les réponses d’erreur sont converties. Vous devrez obtenir le bon convertisseur avec la méthode responseBodyConverter et l’utiliser pour convertir le corps d’erreur de la réponse. Sauf exception, cela pourrait être:

 Converter converter = retrofit.responseBodyConverter(RestError.class, new Annotation[0]); RestError errorResponse = converter.convert(response.errorBody()); 

Essayez ce code

 @Override public void failure(RetrofitError error) { Ssortingng json = new Ssortingng(((TypedByteArray)error.getResponse().getBody()).getBytes()); Log.v("failure", json.toSsortingng()); } 

avec Retrofit 2.0

 @Override public void onFailure(Call call, Throwable t) { Ssortingng message = t.getMessage(); Log.d("failure", message); } 

@LukaCiko répond que je ne travaille plus pour moi en rénovation 1.6.1. Ici comme je le fais maintenant:

  @Override public void failure(RetrofitError retrofitError) { Ssortingng json = new Ssortingng(((TypedByteArray)retrofitError.getResponse().getBody()).getBytes()); //own logic for example ExampleHandlerError error = new Gson().fromJson(json, ExampleHandlerError.class); } 

Two-Liner avec getBodyAs pour obtenir un object JSON.

 JsonObject responseAsJson = (JsonObject) retrofitError.getBodyAs(JsonElement.class); Ssortingng message = responseAsJson.get("error").getAsSsortingng(); //=> "Username already in use" 

Confirmation du travail dans Retrofit 1.x. Vous ne savez pas quelles modifications sont requirejses pour Retrofit 2.x.

En utilisant cela, vous pouvez obtenir le corps de l’erreur

  if (response != null && response.errorBody() != null) { JSONObject jsonObject = new JSONObject(response.errorBody().ssortingng()); Ssortingng error = jsonObject.getSsortingng("error"); } 

Une manière beaucoup plus simple de le faire est de créer une classe capable d’effectuer l’parsing / la conversion pour vous, que vous pouvez appeler n’importe quand et n’importe où.

 public class ApiError { public Ssortingng error = "An error occurred"; public ApiError(Throwable error) { if (error instanceof HttpException) { Ssortingng errorJsonSsortingng = null; try { errorJsonSsortingng = ((HttpException) error).response().errorBody().ssortingng(); } catch (IOException e) { e.printStackTrace(); } JsonElement parsedSsortingng = new JsonParser().parse(errorJsonSsortingng); this.error = parsedSsortingng.getAsJsonObject() .get("error") .getAsSsortingng(); } else { this.error = error.getMessage() != null ? error.getMessage() : this.error; } } } 

Vous pouvez maintenant l’utiliser n’importe où, comme ça

 ApiError error = new ApiError(error) error.error 

C’est tout de cet article de blog (que j’ai écrit).

Donc, après un peu plus de chasse, j’ai trouvé la réponse.

Voici mon rappel d’échec:

 @Override public void failure(RetrofitError retrofitError) { Ssortingng 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); } 

Et voici la méthode appelée pour extraire l’erreur du serveur:

 public static Ssortingng extractServerError(java.io.InputStream is) { Ssortingng serverError = null; Ssortingng serverErrorDescription = null; try { Ssortingng s = convertStreamToSsortingng(is); JSONObject messageObject = new JSONObject(s); serverError = messageObject.optSsortingng("error"); serverErrorDescription = messageObject.optSsortingng("error_description"); if (serverErrorDescription!=null && !serverErrorDescription.equals("")) { return serverErrorDescription; } else { return serverError; } //Ssortingng serverStack = messageObject.getSsortingng("stack"); } catch (Exception e) { Log.e("Basemodel", "Error converting RetrofitError server JSON", e); } return ""; } 

Cela extraira les informations d’erreur envoyées par le service qui est codé dans le JSON.

Je comstack beaucoup de réponses et écrit du code pour réaliser quelque chose de plus beau:

 { "errors": { "email": [ "Email not valid.", "Unable to find the user toto@toto.fr." ] } } 

Je prends tous les éléments dans «email» et les affiche avec le Guava Joiner:

 Ssortingng json = new Ssortingng(((TypedByteArray)error.getResponse() .getBody()).getBytes()); Map map = new Gson().fromJson( json, new TypeToken>>>() {}.getType()); try { List errorsEmail = (List) ((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()); } 

J’avais la même chose. Mon problème était un long champ venant du serveur sous forme de Ssortingng vide "" . Retrofit donnait NumberFormatException car il semble que Gson ne convertisse pas une chaîne vide en long (je suggérerais de le faire 0L ou quelque chose). J’ai donc dû changer:

 long errorCode; 

à

 Ssortingng errorCode; 

Comme il a été dit précédemment, je n’avais pas access au message JSON lors du débogage. J’ai finalement trouvé l’erreur en utilisant la page RequestMaker, peut-être que ça aide quelqu’un d’autre

http://requestmaker.com/