Have you ever needed to change something in an HTTP request? Like, add a new header to control cookies, change the body of a request or simply produce logs to help you on debugging….Those are examples of how OkHttp Interceptors can become your best buddy and help you.
Interceptors are a great choice to monitor, rewrite and retry calls. It’s basically an entity that gets triggered every time the application makes an HTTP request. It is very useful when you need to add behavior to an HTTP request before it gets completed, such as adding an additional control header or even to redirect the original resource location to a completely different new one.
The image below shows how simple is the logic behind an Interceptor, while a client makes an HTTP request to a specific server or API.
There’s no better way to explain how to create an OkHttp Interceptor than building an example. In order to do that, I decided to create a public project with a very simple Android application, where we will intercept an HTTP request and redirect it to a different resource.
The example project
For this example project (it can be cloned here), I decided to create a simple UI that will load an image cover of a movie when you press the “Go” button. Pretty obvious that I’m a fan of the seventh art, right?
Bellow, there’s a switch button to enable or disable the interceptor. When the interceptor is disabled we make a simple request to fetch the cover of Pulp Fiction (thank you, Tarantino!). When the interceptor is enabled, the request will be the same, but the interceptor will change the destination URL to a different movie cover and add a new customized header. Therefore, the response will return the cover of Tarantino’s hopefully next masterpiece instead of the requested Pulp Fiction.
The following image presents the result of the UI when triggered without and with the interceptor.
Under the hood (and I will explain further the details), the same URL is being loaded on the UI. However, once I enable the interceptor, the URL will be replaced for a new one, giving an HTTP response different for the same Request.
How OkHttp Interceptor works
In a nutshell, OkHttp provides two kinds of Interceptors, application interceptors, and network interceptors. The image below illustrates how these interact with the OkHttp core.
- Don’t need to worry about intermediate responses like redirects and retries
- Are always invoked once, even if the HTTP response is served from the cache
- Observe the application’s original intent. Unconcerned with OkHttp-injected headers like If-None-Match
- Permitted to short-circuit and not call Chain.proceed().
- Permitted to retry and make multiple calls to Chain.proceed().
- Able to operate on intermediate responses like redirects and retries
- Not invoked for cached responses that short-circuit the network
- Observe the data just as it will be transmitted over the network
- Access to the Connection that carries the Request
For our application, I will create an application interceptor once we want to intercept the Request and change the endpoint URL. To do that, I need to implement the interface Interceptor available on the OkHttp library.
Creating the Interceptor
As I explained before, interceptors are a mechanism that can rewrite Http, calls among other things. Here’s our simple Interceptor implementation:
Implementing the Interceptor means that we will define the behavior of our Interceptor. We can do it by overwriting the public Response intercept(Chain chain) throws IOException; method.
Our implementation will mimic the original Request, copying the original headers and adding a new one with a <”X-Been”:”Intercepted”> as tag/value pair. With the chain.request().newBuilder() we can replace the received Chain.request().url() to the new location. This will return to the original Request a different Response than the one requested.
In our application example, we don’t need to change the Response, but if we want to (let’s say change the body of the Response) it would be as easy as change the following few lines of code:
Adding the Interceptor to the OkHttp client
An important step in intercepting requests is that OkHttp client must kind of “subscribe” an Interceptor implementation. This will inform the OkHttp engine that one or several Interceptors must be called.
In our case, we need the engine to call our public Response intercept(Chain chain) throws IOException; method implementation. So, to subscribe to our Interceptor implementation we create an OkHttp client like this:
Once our interceptor is an application interceptor, OkHttp client calls the function .addInterceptor(new InterceptRequest()). Otherwise, the subscription should be made calling the .addNetworkInterceptor(new InterceptRequest()).
Now, the only thing missing is the Request, that thankfully is made with OkHttp (which, in case you have missed it, we dissected here). So, let's grab our image resource and call the Request:
As you can see we start by defining a Request with a specific URL. You also might have noticed that I added a .cacheControl(CacheControl.FORCE_NETWORK) to the Request. We need this to specifically force OkHttp to perform a network call, preventing the default behavior from consulting the local cache for the named resource. After that, the Response will be delivered by the OkHttp client execute() call, printing the response code to the console.
And... that's it! This is how you can easily build and Http Interceptor using the OkHttp library.