Manejo de errores personalizado con Retrofit

El REST Api con el que estoy trabajando tiene códigos personalizados y mensajes que se envían desde el servidor dependiendo del estado, me gustaría implementar una Callback<T> personalizada Callback<T> que llama al método de success sólo si el código de estado era 0.

Ejemplo SUCCESS Respuesta recibida del servidor:

 { "code":"0", "message":"success", "data": { "actual_data":"goes_here", "need_to_construct_objects","from_data" } } 

Ejemplo de respuesta a FALLO:

 { "code":"301", "message":"wrong_password", "data": { "actual_data":"will_be_null", "no_need_to_construct_objects","from_data" } } 

code y el message son devueltos por todas las solicitudes, los data contienen los valores de respuesta reales, por lo que me gustaría hacer lo siguiente:

  1. Compruebe el código y el mensaje y sólo llame al success() si el código es 0.
  2. failure() llamada failure() si la solicitud ha fallado o código! = 0
  3. Construir objetos personalizados basados ​​en la respuesta de datos y transmitirlos a través del success()

¿Cuál es la mejor manera de hacer esto? Busqué en todas partes y no pude encontrar una buena solución. Lo único que conseguí fue dejar que todos los objetos personalizados tuvieran los campos de code y message también y verificar sus valores dentro de success() , pero esto podría causar problemas en el futuro si alguien olvida comprobar el code antes de continuar.

Puede hacerlo rápidamente haciendo una clase abstracta que implementa la devolución de llamada y declare sus propios métodos de éxito y fracaso abstractos. La clase abstracta manejará los métodos de devolución de llamada estándar de Retrofit, interpretará la respuesta y llamará a los métodos abstractos en consecuencia.

Creo que otro enfoque posible es anular la interfaz de cliente de Retrofit para crear su propio objeto de respuesta.

Si extiendes OkClient , puede ir así:

 public class CustomClient extends OkClient { @Override public Response execute(Request request) throws IOException { Response originalRespone = super.execute(request); int statusCode = 0; //TODO: read JSON response here (using GSON or similar, and extract status code and message... etc.) //Convert the status code to HTTP standard status codes, according to the documentation you have. if(statusCode == 0) statusCode = 200; //Reconstruct a Response object return new Response(originalResponse.getUrl(), statusCode, originalResponse.getReason() /*should probably replace with parsed message*/, originalResponse.getHeaders(), originalResponse.getBody()); } 

Esto puede ser más trabajo que el manejo de su caso en la devolución de llamada, pero creo que puede ayudar si en algún momento la API transiciones a las convenciones RESTful API.

Esta solución viene con su propio problema sin embargo, porque eso significa que la conversión JSON se ejecutará dos veces. Uno en su cliente, y otro en Retrofit. No estoy seguro de la forma correcta de hacerlo en este momento. Probablemente algo alrededor de TypedInput y un convertidor ficticio que pasa objetos ya convertidos.

Cree un ResponseBodyConverter personalizado como este:

 public class CustomResponseBodyConverter<T> implements Converter<ResponseBody, T> { private final TypeAdapter<T> adapter; CustomResponseBodyConverter(TypeAdapter<T> adapter) { this.adapter = adapter; } @Override public T convert(ResponseBody value) throws IOException,CustomException { String json = ""; try { String body = value.string(); json = new JSONObject(body).getJSONObject("data").toString(); int code = new JSONObject(body).getInt("code"); String message = new JSONObject(body).getString("message"); if(code != 0){ throw new CustomException(message); } } catch (JSONException e) { e.printStackTrace(); } return adapter.fromJson(json); } } 

Al menos esto te ayudará a empezar. Básicamente puede crear su propia devolución de llamada personalizada y luego manejar el éxito. Mira lo que se envió y haz lo que necesites.

  public class CustomCallback implements Callback { @Override public void success(Object o, Response response) { //Check for success //if( Success ) //callback.success(o, response); //else //Check for error //callback.failure(error); } } 

En tu caso, puedes tener una clase que trace tu respuesta de json:

 class CustomResponse { String code; String message; Data data; static class Data { String actualData; String needToContructObjects; String noNeedToContructObjects; } } 

Entonces, puesto que estás de vuelta al mundo de los objetos java, puedes tener un objeto similar a una fábrica dentro de la devolución de llamada del método de éxito que crea el objeto deseado en función de la respuesta personalizada devuelta. Si desea obtener esta respuesta en el fallo de devolución de llamada, reconsideraría el uso de Retrofit, ya que su API no está siguiendo un buen diseño de descanso.

Aunque esto es mucho posible, y la comprensión que no puede estar involucrado en el desarrollo de la API, tenga en cuenta que este no es un buen enfoque de diseño API. Si está enviando una solicitud de inicio de sesión al servidor, puede entender esta solicitud como una solicitud para crear un recurso (una sesión de usuario autenticada, por ejemplo). Si no envía los parámetros correctos (el nombre de usuario y la contraseña correctos en este caso específico), el servidor debe rechazar la solicitud de creación de recursos y devolver un código de estado HTTP de 4 centavos (4xx) indicando que su solicitud no es correcta de algun modo. Retrofit entendería este código de estado 4xx y llamaría a su devolución de llamada falla, donde podría manejar la respuesta apropiadamente.

Es una idea mejor implementar una devolución de llamada personalizada. Usted puede un ejemplo sobre ello abajo.

 public abstract class DefaultRequestCallback<T> implements Callback<T> { public abstract void failure(Meta meta); public abstract void success(T responseBean); @Override public void success(T baseResponseBean, Response response) { // You can check your responsebean's error code and // convert it to a default error BaseResponseBean bean = (BaseResponseBean) baseResponseBean; if (bean == null) { failure(new Meta(ApplicationConstants.ERROR_RETROFIT, "Unknown Error!")); } else if (bean.getMeta() != null && bean.getMeta().getCode() != ApplicationConstants.RESULT_SUCCESS) { failure(bean.getMeta()); } else { success(baseResponseBean); } } @Override public void failure(RetrofitError error) { // Convert default error to your custom error. Meta meta = new Meta(ApplicationConstants.ERROR_RETROFIT, "Error Unknwon"); failure(meta); } } 

Entregue su devolución de llamada personalizada a su método de interfaz de servicio de actualización.

 void yourMethod(DefaultRequestCallback<YourResponseBean> callback); 

Buena suerte.

  • RETROFIT POST Objeto Realm
  • Uso de Retrofit para acceder a los arrays JSON
  • No se puede crear el convertidor para la clase com.squareup.okhttp.ResponseBody
  • Retrofit: agrega un parámetro de lista de cadenas a la solicitud de múltiples partes
  • Detener y reanudar las descargas utilizando Retrofit
  • Excepción Outofmemory utilizando la biblioteca retrofit android
  • Reajustar varios parámetros POST
  • Cómo manejar una cola para repetir solicitudes después de un fallo de red con retroadaptación
  • Retrofit 2: URL dinámica
  • Obtener una matriz JSON de retrofit Response
  • Retrofit da EOFException sólo la primera vez
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.