Search code examples
androidretrofit2rx-java2rx-binding

Handle all types of Retrofit errors properly with rxjava


I'm new to Rxjava with Retrofit and I'm asking for the best right way to handle all possible status in Retrofit using rxjava and rxbinding which includes:

  1. No Internet connection.
  2. Null response from server.
  3. Success response.
  4. Error response and show the error message like Username or password is incorrect.
  5. Other errors like connection reset by peers.

Solution

  • I'm having exception subclass for each important failure response. Exceptions are delivered as Observable.error(), while values are delivered through stream without any wrapping.

    1) No internet - ConnectionException

    2) Null - just NullPointerException

    4) Check for "Bad Request" and throw IncorrectLoginPasswordException

    5) any other error is just NetworkException

    You can map errors with onErrorResumeNext() and map()

    For example

    Typical retrofit method that fetches data from web service:

    public Observable<List<Bill>> getBills() {
        return mainWebService.getBills()
                .doOnNext(this::assertIsResponseSuccessful)
                .onErrorResumeNext(transformIOExceptionIntoConnectionException());
    }
    

    Method that assures response is ok, throws appropriate exceptions otherwise

    private void assertIsResponseSuccessful(Response response) {
        if (!response.isSuccessful() || response.body() == null) {
            int code = response.code();
            switch (code) {
                case 403:
                    throw new ForbiddenException();
                case 500:
                case 502:
                    throw new InternalServerError();
                default:
                    throw new NetworkException(response.message(), response.code());
            }
    
        }
    }
    

    IOException means there is no network connection so I throw ConnectionException

    private <T> Function<Throwable, Observable<T>> transformIOExceptionIntoConnectionException() {
        // if error is IOException then transform it into ConnectionException
        return t -> t instanceof IOException ? Observable.error(new ConnectionException(t.getMessage())) : Observable.error(
                t);
    }
    

    For your login request create new method that will check if login/password are ok.

    And at the end there is

    subscribe(okResponse -> {}, error -> {
    // handle error
    });