Em vez de declarar a chamada da API como você fez:
Observable<MyResponseObject> apiCall(@Body body);
Você também pode declará-lo assim:
Observable<Response<MyResponseObject>> apiCall(@Body body);
Você terá então um Assinante como o seguinte:
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!
}
}
Portanto, as respostas do servidor com um código de erro também serão entregues onNext
e você pode obter o código chamando reponse.code()
.
http://square.github.io/retrofit/2.x/retrofit/retrofit/Response.html
EDIT: OK, finalmente consegui analisar o que o e-nouri disse em seu comentário, ou seja, que apenas os códigos 2xx o farão onNext
. Acontece que ambos estamos certos:
Se a chamada for declarada assim:
Observable<Response<MyResponseObject>> apiCall(@Body body);
ou mesmo isso
Observable<Response<ResponseBody>> apiCall(@Body body);
todas as respostas terminarão em onNext
, independentemente do código de erro. Isso é possível porque tudo está embrulhado em um Response
objeto pelo Retrofit.
Se, por outro lado, a chamada for declarada assim:
Observable<MyResponseObject> apiCall(@Body body);
ou isto
Observable<ResponseBody> apiCall(@Body body);
na verdade, apenas as respostas 2xx irão onNext
. Todo o resto será embrulhado em HttpException
e enviado para onError
. O que também faz sentido, porque sem o Response
invólucro, o que deve ser emitido onNext
? Dado que o pedido não foi bem sucedido, a única coisa sensata a emitir seria null
...