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)
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:
Create two OkHttpClient instances, and by deduction two Retrofit instances, one for the unauthenticated requests, and one for the authenticated requests.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With