En lugar de declarar la llamada a la API como lo hizo:
Observable<MyResponseObject> apiCall(@Body body);
También puedes declararlo así:
Observable<Response<MyResponseObject>> apiCall(@Body body);
A continuación, tendrá un suscriptor como el siguiente:
new Subscriber<Response<StartupResponse>>() {
@Override
public void onCompleted() {}
@Override
public void onError(Throwable e) {
Timber.e(e, "onError: %", e.toString());
// network errors, e. g. UnknownHostException, will end up here
}
@Override
public void onNext(Response<StartupResponse> startupResponseResponse) {
Timber.d("onNext: %s", startupResponseResponse.code());
// HTTP errors, e. g. 404, will end up here!
}
}
Por lo tanto, las respuestas del servidor con un código de error también se enviarán onNext
y puede obtener el código llamando a reponse.code()
.
http://square.github.io/retrofit/2.x/retrofit/retrofit/Response.html
EDITAR: OK, finalmente pude investigar lo que e-nouri dijo en su comentario, es decir, que solo los códigos 2xx lo harán onNext
. Resulta que ambos tenemos razón:
Si la llamada se declara así:
Observable<Response<MyResponseObject>> apiCall(@Body body);
o incluso esto
Observable<Response<ResponseBody>> apiCall(@Body body);
todas las respuestas terminarán en onNext
, independientemente de su código de error. Esto es posible porque todo está envuelto en un Response
objeto por Retrofit.
Si, por el contrario, la llamada se declara así:
Observable<MyResponseObject> apiCall(@Body body);
o esto
Observable<ResponseBody> apiCall(@Body body);
de hecho, solo las respuestas 2xx irán a onNext
. Todo lo demás será envuelto en un HttpException
y enviado a onError
. Lo que también tiene sentido, porque sin la Response
envoltura, ¿a qué se debería emitir onNext
? Dado que la solicitud no tuvo éxito, lo único sensato a emitir sería null
...