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 onNexty 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 Responseobjeto 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 HttpExceptiony enviado a onError. Lo que también tiene sentido, porque sin la Responseenvoltura, ¿a qué se debería emitir onNext? Dado que la solicitud no tuvo éxito, lo único sensato a emitir sería null...