Retrofit – Generic Error Handling and custom exception messages

Retrofit is an HTTP client for Android and Java written by Square Inc.

Today I want to expose a way to handle network exceptions for all your service calls and creating your generic error  messages in a simple way when using Retrofit.

 

GenericException class

We will create a GenericException class where we will put all the types which we want to catch and their corresponding error messages we want to display. SocketException, and I have created a custom exception: InternalServerError. Please find below the code for the GenericException class:

public class GenericException extends IOException {
    Context context;
    String message;

    public GenericException(Context context, Exception e) {
        this.context = context;
        message = context.getString(R.string.str_internet_connection_error);

        if (e instanceof SocketException) {
            message = context.getString(R.string.str_internet_connection_error);

        } else if (e instanceof InternalServerError) {
            message = context.getString(R.string.str_internal_server_error);
        }
    }

    @Override
    public String getMessage() {
        return message;
    }
}

class InternalServerError extends IOException {}

OkHttpClient – Request Interceptor

Retrofit uses OkHttpClient which allows you to add an “interceptor” method. This will allow you to intercept all requests made on your retrofit services. As a result, you can make (common) changes to your requests (e.g add Auth Token) and also inspect the corresponding response and status code.

Below is a code snippet is interceptor method on the Network Module. Notice that we are throwing error using instance of our GenericException class. These exceptions will be propagated to the Activities (or presenter) where the services requests were made.

I checked for 500 status code on the response to catch Internal Server Error and to throw our custom Internal Server Error which will use the custom Exception Message. We also have SocketException to handle timeout exceptions for no internet connection scenarios.

@Singleton
@Provides
public APIService getService(Context context, OkHttpClient.Builder httpClient, Retrofit.Builder retrofit) {
    httpClient.addInterceptor((Interceptor.Chain chain) -> {

        if (!NetworkUtils.isNetworkAvailable(context)) {     // Check if there is internet connection
            throw new GenericException(context, new SocketException());
        }

        Request originalRequest = chain.request();
        // set OAuth token
        Request.Builder newRequest = originalRequest.newBuilder();
        String accessToken = SharedPreferencesRepository.getAuthToken(context);

        newRequest.header("Content-Type", "application/json");
        newRequest.header("Accept", "application/json");
        newRequest.header("Authorization", "Bearer " + accessToken).method(originalRequest.method(), originalRequest.body());

        originalRequest = newRequest.build();

        Response response = chain.proceed(originalRequest); //perform request, here original request will be executed
        int responseCode = response.code();

        if (responseCode == 500) {   // Check for Internal Server errors
            throw new GenericException(context, new InternalServerError());    // Internal Server Error
        }

        if (responseCode == 401) { . // Expired or invalid Auth Token

            // Unauthorized. E.g, Token Expired
            // refreshToken service call
            .
            .
            .
        }

        return response;
    });

    retrofit
        .baseUrl(baseUrl)
        .client(httpClient.build())
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();

    return retrofit.build().create(APIService.class);
}

 

Propagating exception message to the UI

If you are using Rx Java, you will have something as below. The method (Throwable e) will get called whenever there is an exception thrown from the apiService. Exception messages which were defined on the GenericException class are thrown to (Throwable e) method. The exception message “e.getMessage()” can now be displayed to the users, e.g, on an AlertDialog.

Subscription s = apiService.loginRequest(userLoginRequest)
    .compose(RxUtils.applySchedulers())
    .subscribe(
        (UserLoginResponse userLoginResponse) -> {  // on Success
            mView.hideLoading();
            if (userLoginResponse.isSuccess()) {
                mView.onLoginSuccessful();

            } else
                new Throwable(context.getString(R.string.str_login_invalid_credentials));
        },
        (Throwable e) -> { // on Fail

            mView.onLoginFailed(e.getMessage()); // Display exception on an AlertDialog
            mView.hideLoading();
        },
        () -> { // on Complete
            mView.hideLoading();
        });

 

Looking forward for next posts. Let me know if you have any queries or if you want me to share additional codes.

Cheers,

Please Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s