OkHttp 2.0
Square’s HTTP client for Android and Java has a new API.
Written by Jesse Wilson.
OkHttp started as a fork of Android’s HttpURLConnection. That gave us a solid foundation to build upon. Working behind a widely-used API meant that upgrading from AOSP’s HttpURLConnection to ours was easy: just configure URLs stream handler factory.
But we’ve outgrown the HttpURLConnection API. Its fully-synchronous API means that application code needs to manage how requests are dispatched. Requests and responses are together in one class which makes certain operations awkward or inefficient. Most painfully, we’re limited in what we can expose: Was my request redirected? Did the response come from a cache? OkHttp knows the answers to these questions but the HttpURLConnection API offers no way for you to ask them.
Request, Response, and Call
With 2.0, OkHttp introduces three fundamental types: Request, Response, and Call. A call executes a request to produce a response. You can do that synchronously with a blocking call:
**private** **final** OkHttpClient client **=** **new** **OkHttpClient();**
public void run() throws Exception {
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
Call call = client.newCall(request);
Response response = call.execute();
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
System.out.println(response.body().string());
}
Or asynchronously with a callback:
Request request **=** **new** Request**.**Builder**()**
**.**url**(**"http://publicobject.com/helloworld.txt"**)**
**.**build**();**
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override public void onFailure(Request request, IOException e) {
logger.log(Level.SEVERE, "Failed to execute " + request, e);
}
@Override public void onResponse(Response response) throws IOException {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
System.out.println(response.body().string());
}
});
A Request’s Journey
Above we complained that HttpURLConnection lacks APIs to ask how a response was reached. With redirects and caching, that journey can be interesting! One handy example is what happens when OkHttp downloads its own jar file from Maven Central.
Following Redirects
First we’re redirected from the HTTP to the HTTPS site:
> GET [http://repository.sonatype.org/.../redirect?a=okhttp&v=LATEST](http://repository.sonatype.org/.../redirect?a=okhttp&v=LATEST)
< 301 Moved Permanently
< Location: https://repository.sonatype.org/.../redirect?a=okhttp&v=LATEST
Next we’re redirected from the LATEST tag to the specific file we want.
> GET [https://repository.sonatype.org/.../redirect?a=okhttp&v=LATEST](https://repository.sonatype.org/.../redirect?a=okhttp&v=LATEST)
< 307 Temporary Redirect
< Location: https://repository.sonatype.org/.../content/.../okhttp-2.0.0.jar
Finally we download the file. The response includes headers to make caching possible.
> GET [https://repository.sonatype.org/.../content/.../okhttp-2.0.0.jar](https://repository.sonatype.org/.../content/.../okhttp-2.0.0.jar)
< 200 OK
< Last-Modified: Sat, 21 Jun 2014 01:00:00 GMT
< ETag: "{SHA1{4c8d1536dba3812cc1592090dc20c47a4ed3c35e}}"
OkHttp exposes these redirects with Response.priorResponse(). If you’re redirected multiple times, you will have a chain of prior responses. These will be returned in order from last-to-first; reverse them for chronological order:
List**<**Response**>** chainedResponses **=** **new** ArrayList**<>();**
**for** **(**Response r **=** response**;** r **!=** **null;** r **=** r**.**priorResponse**())** **{**
chainedResponses**.**add**(**r**);**
**}**
Collections**.**reverse**(**chainedResponses**);**
for (Response r : chainedResponses) {
System.out.println(r.request().url());
}
Cache and Network Responses
If we re-download the same URL, OkHttp’s response cache may kick in. Responseoffers two methods to check where a response came from: cacheResponse() and networkResponse(). Note that for conditional gets, both will be present!
When downloading a jar file from Maven Central, Response.cacheResponse()returns the cached response from above:
> GET [https://repository.sonatype.org/.../content/.../okhttp-2.0.0.jar](https://repository.sonatype.org/.../content/.../okhttp-2.0.0.jar)
< 200 OK
< Last-Modified: Sat, 21 Jun 2014 01:00:00 GMT
< ETag: "{SHA1{4c8d1536dba3812cc1592090dc20c47a4ed3c35e}}"
This cached response required validation from the server. OkHttp needed to ask, “Has the cached value changed?” Checking Response.networkResponse() confirms that it had not:
> GET [https://repository.sonatype.org/.../content/.../okhttp-2.0.0.jar](https://repository.sonatype.org/.../content/.../okhttp-2.0.0.jar)
> If-Modified-Since: Sat, 21 Jun 2014 01:00:00 GMT
> If-None-Match: "{SHA1{4c8d1536dba3812cc1592090dc20c47a4ed3c35e}}"
< 304 Not Modified
Prior responses from redirects also support cacheResponse() and networkResponse(). Use this to interrogate whether any part of a response used the network.
Upgrading to OkHttp 2.0
OkHttp 2.0 is not backwards-compatible. The changelog describes what’s changed and what’s gone. For example, to continue using the HttpURLConnection API, you will need the optional okhttp-urlconnection dependency. To make upgrading easier, we’ve also released OkHttp 1.6 which is the 1.5 code plus some new 2.0 APIs. Use 1.6 to transition to 2.x APIs.
Get OkHttp from Maven or download it from the project website. Read more code examples in the project’s Recipes doc. Jesse Wilson *Android and jokes.*medium.com