Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrofit and Centralized Error Handling

Tags:

Each request to the server may return error_code. I want to handle these error in one place when I was using AsyncTask I had a BaseAsyncTask like that

public abstract class BaseAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {

    protected Context context;
    private ProgressDialog progressDialog;
    private Result result;

    protected BaseAsyncTask(Context context, ProgressDialog progressDialog) {
        this.context = context;
        this.progressDialog = progressDialog;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    @Override
    protected void onPostExecute(Result result) {
        super.onPostExecute(result);
        HttpResponse<ErrorResponse> response = (HttpResponse<ErrorResponse>) result;
     if(response.getData().getErrorCode() != -1) {
                handleErrors(response.getData());
        }else 
            onResult(result);

    }

    private void handleErrors(ErrorResponse errorResponse) {
    }
     public abstract void onResult(Result result);
    }

But, using retrofit each request has its error handling callback:

                    git.getFeed(user,new Callback<gitmodel>() {
                    @Override
                    public void success(gitmodel gitmodel, Response response) {

                    }

                    @Override
                    public void failure(RetrofitError error) {

                    }
                });
            }
        });

How can I handle all errors in one place?

like image 424
Ma7moud El-Naggar Avatar asked Jul 26 '15 23:07

Ma7moud El-Naggar


People also ask

What is centralized error handling?

Centralized. Centralized way involves some sort of central database or storage of errors (usually a module or a header file) where are all the error messages stored. In code you pass an error code to some function and it does all the work for you. A big plus of this approach is that you have everything in one place.

How do you handle errors in retrofit coroutines?

When using coroutines usually the solution to deal with errors is wrapping your calls with try/catch. That's what we are about to do, but we don't want that spread all over our code, so it's important to keep it in a single place in order to make it less error prone and avoid repeated code.


1 Answers

If you need to get some 'logic' error, then you need some Java logic since it's not a Retrofit feature so basically:

  1. Create a Your implementation Callback that implements the Retrofit Callback
  2. Create a base object that define the method 'isError'
  3. Modify Retrofit RestAdapter in order to get your Callback instead of the Retrofit One

MyCallback.java

import android.util.Log;
import retrofit.Callback;
import retrofit.client.Response;

public abstract class MyCallback<T extends MyObject> implements Callback<T> {

    @Override
    public final void success(T o, Response response) {
        if (o.isError()) {
            // [..do something with error]
            handleLogicError(o);
        }
        else {
            handleSuccess(o, response);
        }
    }

    abstract void handleSuccess(T o, Response response);

    void handleLogicError(T o) {
        Log.v("TAG", "Error because userId is " + o.id);
    }
}

MyObject.java (the base class for all your objects you get from Retrofit)

public class MyObject {
    public long id;
    public boolean isError() {
        return id == 1;
    }
}

MyRealObject.java - a class that extends the base object

public class MyRealObject extends MyObject {
    public long userId;
    public String title;
    public String body;
}

RetroInterface.java - the interface used by retrofit you should be familiar with

import retrofit.http.GET;
import retrofit.http.Path;

public interface RetroInterface {

    @GET("/posts/{id}")
    void sendGet(@Path("id") int id, MyCallback<MyRealObject> callback);

}

And finally the piece of code where you use all the logic

RestAdapter adapter = new RestAdapter.Builder()
    .setEndpoint("http://jsonplaceholder.typicode.com")
    .build();

RetroInterface itf = adapter.create(RetroInterface.class);
itf.sendGet(2, new MyCallback<MyRealObject>() {
    @Override
    void handleSuccess(MyRealObject o, Response response) {
        Log.v("TAG", "success");
    }

    @Override
    public void failure(RetrofitError error) {
        Log.v("TAG", "failure");
    }
});

If you copy and paste this code, you'll get an error when you'll execute the itf.sendGet(1, new MyCallback..) and a success for itf.sendGet(2, new MyCallback...)

like image 58
Mimmo Grottoli Avatar answered Sep 24 '22 00:09

Mimmo Grottoli