Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrofit 2.0 multiple interceptors

I am working with retrofit and need to be able to use multiple interceptors. Currently I am using one to automatically append an auth token but i need to be able to make calls with no auth token. If i add another interceptor with no auth token in the header how do I use that one instead of the auth token interceptor.

    val interceptor: Interceptor = Interceptor { chain ->
    val newRequest = chain.request().newBuilder().
            addHeader("Auth_Token", pref.getString(PSPreferences.prefAuthKey, "")).
            cacheControl(CacheControl.FORCE_NETWORK).
            build()
    chain.proceed(newRequest)
}

okHttpClient = OkHttpClient.Builder().
        readTimeout(1, TimeUnit.MINUTES).
        connectTimeout(1, TimeUnit.MINUTES).
        addInterceptor(interceptor).build()

val retrofitInstance = Retrofit.Builder()
        .baseUrl(APIEndpointInterface.BASE_URL)
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
apiInterface = retrofitInstance.create<APIEndpointInterface>(APIEndpointInterface::class.java)
like image 282
Doug Ray Avatar asked Mar 08 '23 19:03

Doug Ray


1 Answers

OkHttpClient maintains a list of the interceptors which you can access, however it is an unmodifiable collection.

This leaves us with three options I believe:

  1. Create two OkHttpClient instances, and by deduction two Retrofit instances, one for the unauthenticated requests, and one for the authenticated requests.

  2. Check if you should use the interceptor, e.g. in your authentication interceptor, you can first check if there exists a key in your preferences for the token, and if so use it; if not, you simply proceed without modifying anything. You do this for your unauthenticated interceptor too. I think this is the easiest solution for your case.

  3. Create a single interceptor, which will maintain a modifiable list of interceptors which you can add and remove at will. You would need to keep a reference to this interceptor, maybe make it a Singleton.

For the third option, I have provided a very simple example:

public class HttpRequestResponseInterceptor implements Interceptor {

    public final List<RequestInterceptor> requestInterceptors = new ArrayList<>();
    public final List<ResponseInterceptor> responseInterceptors = new ArrayList<>();

    @Override
    public Response intercept(Chain chain) throws IOException {

        Request request = chain.request();

        for (RequestInterceptor interceptor : requestInterceptors) {
            request = interceptor.intercept(request);
        }

        Response response = chain.proceed(request);

        for (ResponseInterceptor interceptor : responseInterceptors) {
            response = interceptor.intercept(response);
        }

        return response;
    }

    public interface RequestInterceptor {
        Request intercept(Request request) throws IOException;
    }

    public interface ResponseInterceptor {
        Response intercept(Response response) throws IOException;
    }
}

In this case you would need to implement the custom interfaces RequestInterceptor and ResponseInterceptor.

An example of what an implementation of these interfaces would look like:

public class ExampleInterceptor implements HttpRequestResponseInterceptor.RequestInterceptor,
 HttpRequestResponseInterceptor.ResponseInterceptor {

    @Override
    public Request intercept(Request request) throws IOException {
        return request.newBuilder().addHeader("REQUEST_HEADER", "EXAMPLE").build();
    }

    @Override
    public Response intercept(Response response) throws IOException {
        return response.newBuilder().addHeader("RESPONSE_HEADER", "EXAMPLE").build();
    }
}

You would then need to add this interceptor to our main interceptor twice, once to requestInterceptors and once to responseInterceptors (or only to one of these if it intercepts only requests or only responses).

This example is far from complete. The benefit of this solution is that it adds the ability to add and remove interceptors without having to recreate the OkHttpClient instance. It requires extra work if you want to support retrying requests, for example.

like image 70
TGO Avatar answered Mar 20 '23 03:03

TGO