SlideShare a Scribd company logo
Efficient HTTP Apis
A walk through http/2 via okhttp
@adrianfcole
introduction
hello http api!
hello okhttp!
uh oh.. scale!
hello http/2!
wrapping up
introduction
hello http api!
hello okhttp!
uh oh.. scale!
hello http/2!
wrapping up
* Can be blamed for the http/2 defects in okhttp!
@adrianfcole
• engineer at Pivotal on Spring Cloud
• lots of open source work
• focus on cloud computing
okhttp
• HttpURLConnection Apache HttpClient compatible
• designed for java and android
• BDFL: Jesse Wilson from square
https://github.com/square/okhttp
introduction
hello http api!
hello okhttp!
uh oh.. scale!
hello http/2!
wrapping up
$ curl https://apihost/things 
-H ‘SecurityToken: b08c85073c1a2d02’ 
-H ‘Accept: application/json’
[
{
"id": 1,
"owner_id": 0,
"name": "Able"
},
...
{
"id": 26,
"owner_id": 0,
$ curl https://apihost/things/2 
-H ‘SecurityToken: b08c85073c1a2d02’ 
-H ‘Accept: application/json’
{
"id": 2,
"owner_id": 0,
"name": "Beatific"
}
$ curl -X POST https://apihost/things 
-H ‘SecurityToken: b08c85073c1a2d02’ 
-H ‘Content-Type: application/json’ -d
’{
"name": "Open-minded"
}’
$ curl -X DELETE https://apihost/things/2 
-H ‘SecurityToken: b08c85073c1a2d02’
json apis are so simple
$ curl https://apihost/things 
-H ‘SecurityToken: b08c85073c1a2d02’ 
-H ‘Accept: application/json’
[
{
"id": 1,
"owner_id": 0,
"name": "Able"
},
...
{
"id": 26,
"owner_id": 0,
"name": "Zest"
}
$ curl https://apihost/things/2 
-H ‘SecurityToken: b08c85073c1a2d02’ 
-H ‘Accept: application/json’
{
"id": 2,
"owner_id": 0,
"name": "Beatific"
}
$ curl -X POST https://apihost/things 
-H ‘SecurityToken: b08c85073c1a2d02’ 
-H ‘Content-Type: application/json’ -d
’{ "name": "Open-minded" }’
$ curl -X DELETE https://apihost/things/2 
-H ‘SecurityToken: b08c85073c1a2d02’
so many bytes?!
1642!
$ curl --compress https://apihost/things 
-H ‘SecurityToken: b08c85073c1a2d02’ 
-H ‘Accept: application/json’
-H ‘Accept-encoding: gzip, deflate’
[
{
"id": 1,
"owner_id": 0,
"name": "Able"
},
...
{
"id": 26,
"owner_id": 0,
"name": "Zest"
$ curl https://apihost/things/2 
-H ‘SecurityToken: b08c85073c1a2d02’ 
-H ‘Accept: application/json’
{
"id": 2,
"owner_id": 0,
"name": "Beatific"
}
$ curl -X POST https://apihost/things 
-H ‘SecurityToken: b08c85073c1a2d02’ 
-H ‘Content-Type: application/json’ -d
’{ "name": "Open-minded" }’
$ curl -X DELETE https://apihost/things/2 
-H ‘SecurityToken: b08c85073c1a2d02’
now with gzip
318
java + gson
url = new URL(“https://apihost/things”);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty(“SecurityToken”, “b08c85073c1a2d02”);
connection.setRequestProperty(“Accept”, “application/json”);
connection.setRequestProperty(“Accept-Encoding”, "gzip, deflate");
is = connection.getInputStream();
isr = new InputStreamReader(new GZIPInputStream(is));
things = new Gson().fromJson(isr, new TypeToken<List<Thing>>(){});
okhttp + gson
client = new OkHttpClient();
url = new URL(“https://apihost/things”);
connection = new OkUrlFactory(client).open(url);
connection.setRequestProperty(“SecurityToken”, “b08c85073c1a2d02”);
connection.setRequestProperty(“Accept”, “application/json”);
connection.setRequestProperty(“Accept-Encoding”, "gzip, deflate");
is = connection.getInputStream();
isr = new InputStreamReader(is); // automatic gunzip
things = new Gson().fromJson(isr, new TypeToken<List<Thing>>(){});
is.close();
We won!
• List body reduced from 1642 to 318 bytes!
• We saved some lines using OkHttp
• Concession: cpu for compression, curl is a
little verbose.
introduction
hello http api!
hello okhttp!
uh oh.. scale!
hello http/2!
wrapping up
okhttp
• v2.5 has lots of stuff since v1
• buffer, call, cache, interceptor, url
• http/2 and WebSocket support
• Apache adapter
https://github.com/square/okhttp
okhttp
client = new OkHttpClient();
request = new Request.Builder()
.url(“https://apihost/things”)
.header(“SecurityToken”, “b08c85073c1a2d02”)
.header(“Accept”, “application/json”)
.header(“Accept-Encoding”, "gzip, deflate”).build();
// ^^ look, ma.. I’m immutable!
reader = client.newCall(request).execute().body().charStream();
things = new Gson().fromJson(reader, new TypeToken<List<Thing>>(){});
• OkHttp has its own api, which has a
concise way to get bytes or chars
(via okio).
okhttp call
client = new OkHttpClient();
request = new Request.Builder()
.url(“https://apihost/things”)
.header(“SecurityToken”, “b08c85073c1a2d02”)
.header(“Accept”, “application/json”)
.header(“Accept-Encoding”, "gzip, deflate").build();
call = client.newCall(request);
call.enqueue(new ParseThingsCallback());
call.cancel(); // changed my mind
• OkHttp also has an async api,
which (also) supports cancel!
• # Explicity trust certs for your properties
• new CertificatePinner.Builder()
• .add(“my.biz”, publicKeySHA1)
• .add(“*.my.biz”, publicKeySHA1)
• .build()
• # Respond to authentication challenges
• new Authenticator() {
• public Request authenticate(Proxy p, Response rsp) {
• return rsp.request().newBuilder()
• .header(“Authorization", “Bearer …”)
• # Set your own floor for TLS
• new ConnectionSpec.Builder(MODERN_TLS)
okhttp
security
okhttp interceptor
client = new OkHttpClient();
client.interceptors().add((chain) ->

chain.proceed(chain.request().newBuilder()

.addHeader("SecurityToken", securityToken.get())

.build())

);
request = new Request.Builder()
.url(“https://apihost/things”)
.header(“Accept-Encoding”, "gzip, deflate").build();
call = client.newCall(request);
call.enqueue(new ParseThingsCallback());
• Now you can change your
security token!
okio
• ByteString
• Unbounded Buffer
• Source/Sink abstraction
https://github.com/square/okio
// Okio is (more than) a prettier DataInputStream
BufferedSink sink = Okio.buffer(Okio.sink(file));
sink.writeUtf8("Hello, java.io file!”);
sink.writeLong(1000000000000000L);
sink.close();
// Streaming writes with no housekeeping
new RequestBody() {
@Override public void writeTo(BufferedSink sink) throws IOException {
sink.writeUtf8("Numbersn");
sink.writeUtf8("-------n");
for (int i = 2; i <= 997; i++) {
sink.writeUtf8(String.format(" * %s = %sn", i, factor(i)));
}
}
—snip—
// Lazy, composable bodies
new MultipartBuilder("123")
.addPart(RequestBody.create(MediaType.parse(“text/plain”, "Quick"))
.addPart(new StreamingBody("Brown"))
okio
samples
samples
• Starters like web crawler
• How-to guide w/ recipes
https://github.com/square/okhttp/tree/master/samples
introduction
hello http api!
hello okhttp!
uh oh.. scale!
hello http/2!
wrapping up
Hey.. List #1 is slow!
368!
Ask Ilya why!
• TCP connections need 3-
way handshake.
• TLS requires up to 2
more round-trips.
• Read High Performance
Browser Networking
http://chimera.labs.oreilly.com/books/1230000000545
HttpUrlConnection
• http.keepAlive - should connections should be
pooled at all? Default is true.
• http.maxConnections - maximum number of idle
connections to each host in the pool. Default is 5.
• get[Input|Error]Stream().close() - recycles the
connection, if fully read.
• disconnect() - removes the connection.
Don’t forget to read!
...
is = tryGetInputStream(connection);
isr = new InputStreamReader(is);
things = new Gson().fromJson(isr, new TypeToken<List<Thing>>(){});
...
InputStream tryGetInputStream(HttpUrlConnection connection) throws IOException {
try {
return connection.getInputStream();
} catch (IOException e) {
InputStream err = connection.getErrorStream();
  while (in.read() != -1); // skip
err.close();
throw e;
}
or just use okhttp
try (ResponseBody body = client.newCall(request).execute().body())
{
// connection will be cleaned on close.
}
client.newCall(request).enqueue(new Callback() {
@Override public void onFailure(Request request, IOException e) {
// body is implicitly closed on failure
}
@Override public void onResponse(Response response) {
// make sure you call response.body().close() when done
}
});
We won!
• Recycled socket requests are much faster
and have less impact on the server.
• Concessions: must read responses,
concurrency is still bounded by sockets.
Let’s make List #2 free
Cache-Control: private, max-age=60, s-maxage=0
Vary: SecurityToken
Step 1: add a little magic to your server response
Step 2: make sure you are using a cache!
client.setCache(new Cache(dir, 10_MB));
Step 3: pray your developers don’t get clever
// TODO: stupid server sends stale data without this
new Request.Builder().url(”https://apihost/things?time=” + currentTimeMillis());
// Limit cache duration
thisMessageWillSelfDestruct = new Request.Builder()
.url(“https://foo.com/weather”)
.cacheControl(new CacheControl.Builder().maxAge(12, HOURS).build())
.build();
// Opt-out of response caching
notStored = new Request.Builder()
.url(“https://foo.com/private”)
.cacheControl(CacheControl.FORCE_NETWORK)
.build();
// Offline mode
offline = new Request.Builder()
.url(“https://foo.com/image”)
.cacheControl(CacheControl.FORCE_CACHE)
.build();
okhttp cache recipes
We won again!
• No time or bandwidth used for cached
responses
• No application-specific cache bugs code.
• Concessions: only supports “safe methods”,
caching needs to be tuned.
introduction
hello http api!
hello okhttp!
uh oh.. scale!
hello http/2!
wrapping up
http/1.1
• rfc2616 - June 1999
• text-based framing
• defined semantics of the web
http://www.w3.org/Protocols/rfc2616/rfc2616.html
FYI: RFC 2616 is dead!
• RFC 7230-5 replaces RFC 2616.
• Checkout details on www.mnot.net/blog
spdy/3.1
http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1
• google - Sep 2013
• binary framing
• retains http/1.1 semantics
• concurrent multiplexed streams
http/2
https://tools.ietf.org/html/rfc7540
• rfc7540 - May 2015
• binary framing
• retains http/1.1 semantics
• concurrent multiplexed streams
multiplexing
header compression
flow control
priority
server push
http/2 headline features
multiplexing
header compression
server push
http/2 headline features
Looking at the whole
message
Request: request line, headers, and body
Response: status line, headers, and body
http/1.1 round-trip
GZIPPED DATA
Content-Length: 318
Cache-Control: private, max-age=60, s-
maxage=0
Vary: SecurityToken
Date: Sun, 02 Feb 2014 20:30:38 GMT
Content-Type: application/json
Content-Encoding: gzip
Host: apihost
SecurityToken: b08c85073c1a2d02
Accept: application/json
Accept-encoding: gzip, deflate
GET /things HTTP/1.1
HTTP/1.1 200 OK
• http/1.1 sends requests and
responses one at a time
over a network connection
http/2 round-trip
GZIPPED DATA
:status: 200
content-length: 318
cache-control: private, max-age=60, s-
maxage=0
vary: SecurityToken
date: Sun, 02 Feb 2014 20:30:38 GMT
content-type: application/json
:method: GET
:authority: apihost
:path: /things
securitytoken: b08c85073c1a2d02
accept: application/json
accept-encoding: gzip, deflate
HEADERS
Stream: 3
Flags: END_HEADERS, END_STREAM
HEADERS
Stream: 3
Flags: END_HEADERS
DATA
Stream: 3
Flags: END_STREAM
• http/2 breaks up messages
into stream-scoped frames
Interleaving
HEADERS
Stream: 5
Flags: END_HEADERS, END_STREAM
HEADERS
Stream: 3
Flags: END_HEADERS
DATA
Stream: 5
Flags:
DATA
Stream: 5
Flags: END_STREAM
HEADERS
Stream: 3
Flags: END_HEADERS, END_STREAM
HEADERS
Stream: 5
Flags: END_HEADERS
DATA
Stream: 3
Flags: END_STREAM
• http/2 multiplexes a network
connection by interleaving
request/response frames
Canceling a Stream
HEADERS
Stream: 5
Flags: END_HEADERS, END_STREAM
HEADERS
Stream: 3
Flags: END_HEADERS
DATA
Stream: 5
Flags:
HEADERS
Stream: 3
Flags: END_HEADERS, END_STREAM
HEADERS
Stream: 5
Flags: END_HEADERS
DATA
Stream: 3
Flags: END_STREAM
RST_STREAM
Stream: 5
ErrorCode: CANCEL
• interrupts a response without
affecting the connection
control frames
HEADERS
Stream: 5
HEADERS
Stream: 3
DATA
Stream: 5
DATA
Stream: 3
HEADERS
Stream: 3
HEADERS
Stream: 5
SETTINGS
Stream: 0
SETTINGS
Stream: 0
DATA
Stream: 5
• connection-scoped frames
allow runtime updates, like
flow-control
OkHttp/2 Architecture
Frame
Reader
Thread
Frame
Writer
Lock
Control
Frame
Queue
FramedConnection
multiplexing
header compression
server push
http/2 headline features
http/1.1 headers
GZIPPED DATA
Content-Length: 318
Cache-Control: private, max-age=60, s-
maxage=0
Vary: SecurityToken
Date: Sun, 02 Feb 2014 20:30:38 GMT
Content-Type: application/json
Content-Encoding: gzip
Host: apihost
SecurityToken: b08c85073c1a2d02
Accept: application/json
Accept-encoding: gzip, deflate
GET /things HTTP/1.1
HTTP/1.1 200 OK
168!
195!
318
• You can gzip
data, but not
headers!
header compression
GZIPPED DATA
:status: 200
content-length: 318
cache-control: private, max-age=60, s-maxage=0
vary: SecurityToken
date: Sun, 02 Feb 2014 20:30:38 GMT
content-type: application/json
content-encoding: gzip
:method: GET
:authority: apihost
:path: /things
securitytoken: b08c85073c1a2d02
accept: application/json
accept-encoding: gzip, deflate
HEADERS
Stream: 3
Flags: END_HEADERS, END_STREAM
HEADERS
Stream: 3
Flags: END_HEADERS
DATA
Stream: 3
Flags: END_STREAM
8 bytes
52 bytes compressed
8 bytes
85 bytes compressed
• 161 byte overhead
instead of 363 8 bytes
indexed headers!
GZIPPED DATA
:status: 200
content-length: 318
cache-control: private, max-age=60, s-maxage=0
vary: SecurityToken
date: Sun, 02 Feb 2014 20:30:39 GMT
content-type: application/json
content-encoding: gzip
:method: GET
:authority: apihost
:path: /things
securitytoken: b08c85073c1a2d02
accept: application/json
accept-encoding: gzip, deflate
HEADERS
Stream: 3
Flags: END_HEADERS, END_STREAM
HEADERS
Stream: 3
Flags: END_HEADERS
DATA
Stream: 3
Flags: END_STREAM
8 bytes
28 bytes compressed
8 bytes
30 bytes compressed
• 82 byte overhead
instead of 363 8 bytes
hpack
http://tools.ietf.org/html/rfc7541
• rfc7540 - May 2015
• static and dynamic table
• huffman encoding
multiplexing
header compression
server push
http/2 headline features
push promise
:method: GET
:path: /things
...
HEADERS
Stream: 3
HEADERS
Stream: 3
DATA
Stream: 4
:method: GET
:path: /users/0
...
PUSH_PROMISE
Stream: 3
Promised-Stream: 4
HEADERS
Stream: 4
push
response
goes into
cache
DATA
Stream: 3
Server guesses a
future request or
indicates a cache
invalidation
okhttp + http/2
• OkHttp 2.3+ supports http/2 on TLS+ALPN connections.
• Works out of the box on Android
• Java needs hacks until JEP 244
For now, add jetty’s ALPN to your bootclasspath.
* Verify version matches your JRE *
$ java -Xbootclasspath/p:/path/to/alpn-boot-8.1.4.v20150727.jar
We won!
• 1 socket for 100+ concurrent streams.
• Advanced features like flow control,
cancellation and cache push.
• Dramatically less header overhead.
okhttp tools
• There are tools that leverage OkHttp natively…
• including its http/2 features.
MockWebServer
SSLSocketFactory factory = SslContextBuilder.localhost().getSocketFactory();
OkHttpClient client = new OkHttpClient()
.setSslSocketFactory(factory);
@Rule public final MockWebServer server = new MockWebServer()
.setSslSocketFactory(factory);
@Test public void evenWithHttp2SlowResponsesKill() throws Exception {
server.enqueue(new MockResponse().setBody(lotsOfThings)
.throttleBody(1024, 1, SECONDS)); // slow connection 1KiB/second
request = new Request.Builder()
.url(server.getUrl(”/”) + ”things”)
—snip—
• MockWebServer uses http/2
by default when using TLS
Retrofit 2
@Headers("Accept-Encoding: gzip, deflate”)
interface ThingService {
@GET("things") Single<List<Things> list(); // RxJava support!
}
retrofit = new Retrofit.Builder()
.client(client)
.baseUrl(“https://apihost/“)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
thingsService = retrofit.create(ThingService.class);
subscription = thingsService.iist().subscribe(System.out::println)
• Retrofit 2 extends OkHttp
with api model binding
okcurl
$ java -Xbootclasspath/p:alpn-boot.jar -jar okcurl.jar https://twitter.com
-X HEAD --frames
>> CONNECTION 505249202a20485454502f322e300d0a0d0a534d0d0a0d0a
<< 0x00000000 6 SETTINGS
>> 0x00000000 6 SETTINGS
>> 0x00000000 4 WINDOW_UPDATE
>> 0x00000000 0 SETTINGS ACK
>> 0x00000003 60 HEADERS END_STREAM|END_HEADERS
<< 0x00000000 0 SETTINGS ACK
<< 0x00000003 2097 HEADERS END_STREAM|END_HEADERS
>> 0x00000000 8 GOAWAY
introduction
hello http api!
hello okhttp!
uh oh.. scale!
hello http/2!
wrapping up
Engage!
• Consider http/2 or at least spdy!
• Check-out okhttp and friends
• Test http/2 load balancers like google cloud
https://github.com/square/okhttp/tree/master/mockwebserver
http://square.github.io/retrofit/
https://cloud.google.com/compute/docs/load-balancing/http/
Thank you!
github square/okhttp @adrianfcole

More Related Content

What's hot (20)

PDF
Just curl it!
Daniel Stenberg
 
PDF
HTTP2 is Here!
Andy Davies
 
PPTX
HTTP/2 Introduction
Walter Liu
 
PPTX
Altitude San Francisco 2018: Programming the Edge
Fastly
 
PDF
HTTP2:新的机遇与挑战
Jerry Qu
 
PPTX
Introduction to HTTP/2
Ido Flatow
 
PDF
Revisiting HTTP/2
Fastly
 
PDF
HTTP/2 Update - FOSDEM 2016
Daniel Stenberg
 
PPTX
Altitude San Francisco 2018: Testing with Fastly Workshop
Fastly
 
PDF
Http2 right now
Daniel Stenberg
 
PDF
ZN27112015
Denis Kolegov
 
PDF
HTTP 2.0 Why, How and When
Codemotion
 
PDF
So that was HTTP/2, what's next?
Daniel Stenberg
 
PDF
HTTP2 & HPACK #pyfes 2013-11-30
Jxck Jxck
 
PDF
Covert Timing Channels using HTTP Cache Headers
Denis Kolegov
 
PDF
curl better
Daniel Stenberg
 
PDF
HTTP/3
Daniel Stenberg
 
PPTX
Introducing HTTP/2
Ido Flatow
 
PPTX
5 steps to faster web sites & HTML5 games - updated for DDDscot
Michael Ewins
 
PDF
HTTP 2.0 – What do I need to know?
Sigma Software
 
Just curl it!
Daniel Stenberg
 
HTTP2 is Here!
Andy Davies
 
HTTP/2 Introduction
Walter Liu
 
Altitude San Francisco 2018: Programming the Edge
Fastly
 
HTTP2:新的机遇与挑战
Jerry Qu
 
Introduction to HTTP/2
Ido Flatow
 
Revisiting HTTP/2
Fastly
 
HTTP/2 Update - FOSDEM 2016
Daniel Stenberg
 
Altitude San Francisco 2018: Testing with Fastly Workshop
Fastly
 
Http2 right now
Daniel Stenberg
 
ZN27112015
Denis Kolegov
 
HTTP 2.0 Why, How and When
Codemotion
 
So that was HTTP/2, what's next?
Daniel Stenberg
 
HTTP2 & HPACK #pyfes 2013-11-30
Jxck Jxck
 
Covert Timing Channels using HTTP Cache Headers
Denis Kolegov
 
curl better
Daniel Stenberg
 
Introducing HTTP/2
Ido Flatow
 
5 steps to faster web sites & HTML5 games - updated for DDDscot
Michael Ewins
 
HTTP 2.0 – What do I need to know?
Sigma Software
 

Viewers also liked (20)

PDF
Chicago Hadoop Users Group: Enterprise Data Workflows
Paco Nathan
 
PDF
Spring 3.1 and MVC Testing Support - 4Developers
Sam Brannen
 
PDF
Reactive Programming With Akka - Lessons Learned
Daniel Sawano
 
PDF
A Sceptical Guide to Functional Programming
Garth Gilmour
 
PDF
The no-framework Scala Dependency Injection Framework
Adam Warski
 
PDF
Actor Based Asyncronous IO in Akka
drewhk
 
PDF
Effective akka scalaio
shinolajla
 
PDF
Beginning Haskell, Dive In, Its Not That Scary!
priort
 
PPTX
C*ollege Credit: Creating Your First App in Java with Cassandra
DataStax
 
PDF
Building ‘Bootiful’ microservices cloud
Idan Fridman
 
PDF
Effective Actors
shinolajla
 
KEY
Curator intro
Jordan Zimmerman
 
PDF
Using Apache Solr
pittaya
 
PDF
Effective Scala (SoftShake 2013)
mircodotta
 
PDF
Composable and streamable Play apps
Yevgeniy Brikman
 
PDF
Clean Architecture
Badoo
 
PDF
Introducing Clean Architecture
Roc Boronat
 
PDF
An example of Future composition in a real app
Phil Calçado
 
PPTX
Clean architecture
andbed
 
PDF
Design for developers
Johan Ronsse
 
Chicago Hadoop Users Group: Enterprise Data Workflows
Paco Nathan
 
Spring 3.1 and MVC Testing Support - 4Developers
Sam Brannen
 
Reactive Programming With Akka - Lessons Learned
Daniel Sawano
 
A Sceptical Guide to Functional Programming
Garth Gilmour
 
The no-framework Scala Dependency Injection Framework
Adam Warski
 
Actor Based Asyncronous IO in Akka
drewhk
 
Effective akka scalaio
shinolajla
 
Beginning Haskell, Dive In, Its Not That Scary!
priort
 
C*ollege Credit: Creating Your First App in Java with Cassandra
DataStax
 
Building ‘Bootiful’ microservices cloud
Idan Fridman
 
Effective Actors
shinolajla
 
Curator intro
Jordan Zimmerman
 
Using Apache Solr
pittaya
 
Effective Scala (SoftShake 2013)
mircodotta
 
Composable and streamable Play apps
Yevgeniy Brikman
 
Clean Architecture
Badoo
 
Introducing Clean Architecture
Roc Boronat
 
An example of Future composition in a real app
Phil Calçado
 
Clean architecture
andbed
 
Design for developers
Johan Ronsse
 
Ad

Similar to Efficient HTTP Apis (20)

PPTX
Performance #4 network
Vitali Pekelis
 
PDF
Android Performance #4: Network
Yonatan Levin
 
PPT
Android httpclient
allanh0526
 
PPTX
Extend your REST API
Alexey Tokar
 
PDF
Connecting to the network
Mu Chun Wang
 
PPTX
Android and REST
Roman Woźniak
 
PDF
OWASP Proxy
Security B-Sides
 
PDF
Connecting to Web Services on Android
sullis
 
PDF
Infinum Android Talks #01 - Retrofit
Infinum
 
PDF
RefCard RESTful API Design
OCTO Technology
 
PDF
Web Services and Android - OSSPAC 2009
sullis
 
PDF
JSON API Standards
Lucas Bicca
 
PDF
Embracing the-power-of-refactor
Xiaojun REN
 
PDF
Non Blocking I/O for Everyone with RxJava
Frank Lyaruu
 
PDF
HTTP Request Smuggling via higher HTTP versions
neexemil
 
PDF
Connecting to-web-services-on-android-4577
sharvari123
 
PPTX
Demystifying REST
Kirsten Hunter
 
PDF
Building sustainable RESTFul services
Ortus Solutions, Corp
 
PPTX
Building a Reactive RESTful API with Akka Http & Slick
Zalando Technology
 
PPTX
The lazy programmers guide to consuming web services
mamnun
 
Performance #4 network
Vitali Pekelis
 
Android Performance #4: Network
Yonatan Levin
 
Android httpclient
allanh0526
 
Extend your REST API
Alexey Tokar
 
Connecting to the network
Mu Chun Wang
 
Android and REST
Roman Woźniak
 
OWASP Proxy
Security B-Sides
 
Connecting to Web Services on Android
sullis
 
Infinum Android Talks #01 - Retrofit
Infinum
 
RefCard RESTful API Design
OCTO Technology
 
Web Services and Android - OSSPAC 2009
sullis
 
JSON API Standards
Lucas Bicca
 
Embracing the-power-of-refactor
Xiaojun REN
 
Non Blocking I/O for Everyone with RxJava
Frank Lyaruu
 
HTTP Request Smuggling via higher HTTP versions
neexemil
 
Connecting to-web-services-on-android-4577
sharvari123
 
Demystifying REST
Kirsten Hunter
 
Building sustainable RESTFul services
Ortus Solutions, Corp
 
Building a Reactive RESTful API with Akka Http & Slick
Zalando Technology
 
The lazy programmers guide to consuming web services
mamnun
 
Ad

Recently uploaded (20)

PPTX
Future Tech Innovations 2025 – A TechLists Insight
TechLists
 
PDF
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
PDF
AI Agents in the Cloud: The Rise of Agentic Cloud Architecture
Lilly Gracia
 
PPTX
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
PDF
Go Concurrency Real-World Patterns, Pitfalls, and Playground Battles.pdf
Emily Achieng
 
PDF
UPDF - AI PDF Editor & Converter Key Features
DealFuel
 
PPTX
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
PDF
Automating Feature Enrichment and Station Creation in Natural Gas Utility Net...
Safe Software
 
PDF
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
PPTX
Agentforce World Tour Toronto '25 - MCP with MuleSoft
Alexandra N. Martinez
 
PDF
Kit-Works Team Study_20250627_한달만에만든사내서비스키링(양다윗).pdf
Wonjun Hwang
 
PDF
LOOPS in C Programming Language - Technology
RishabhDwivedi43
 
PDF
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
PDF
POV_ Why Enterprises Need to Find Value in ZERO.pdf
darshakparmar
 
PDF
Transcript: Book industry state of the nation 2025 - Tech Forum 2025
BookNet Canada
 
PDF
ICONIQ State of AI Report 2025 - The Builder's Playbook
Razin Mustafiz
 
PDF
“Computer Vision at Sea: Automated Fish Tracking for Sustainable Fishing,” a ...
Edge AI and Vision Alliance
 
PDF
SIZING YOUR AIR CONDITIONER---A PRACTICAL GUIDE.pdf
Muhammad Rizwan Akram
 
PPTX
Mastering ODC + Okta Configuration - Chennai OSUG
HathiMaryA
 
PDF
UiPath DevConnect 2025: Agentic Automation Community User Group Meeting
DianaGray10
 
Future Tech Innovations 2025 – A TechLists Insight
TechLists
 
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
AI Agents in the Cloud: The Rise of Agentic Cloud Architecture
Lilly Gracia
 
From Sci-Fi to Reality: Exploring AI Evolution
Svetlana Meissner
 
Go Concurrency Real-World Patterns, Pitfalls, and Playground Battles.pdf
Emily Achieng
 
UPDF - AI PDF Editor & Converter Key Features
DealFuel
 
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
Automating Feature Enrichment and Station Creation in Natural Gas Utility Net...
Safe Software
 
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
Agentforce World Tour Toronto '25 - MCP with MuleSoft
Alexandra N. Martinez
 
Kit-Works Team Study_20250627_한달만에만든사내서비스키링(양다윗).pdf
Wonjun Hwang
 
LOOPS in C Programming Language - Technology
RishabhDwivedi43
 
The Rise of AI and IoT in Mobile App Tech.pdf
IMG Global Infotech
 
POV_ Why Enterprises Need to Find Value in ZERO.pdf
darshakparmar
 
Transcript: Book industry state of the nation 2025 - Tech Forum 2025
BookNet Canada
 
ICONIQ State of AI Report 2025 - The Builder's Playbook
Razin Mustafiz
 
“Computer Vision at Sea: Automated Fish Tracking for Sustainable Fishing,” a ...
Edge AI and Vision Alliance
 
SIZING YOUR AIR CONDITIONER---A PRACTICAL GUIDE.pdf
Muhammad Rizwan Akram
 
Mastering ODC + Okta Configuration - Chennai OSUG
HathiMaryA
 
UiPath DevConnect 2025: Agentic Automation Community User Group Meeting
DianaGray10
 

Efficient HTTP Apis

  • 1. Efficient HTTP Apis A walk through http/2 via okhttp @adrianfcole
  • 2. introduction hello http api! hello okhttp! uh oh.. scale! hello http/2! wrapping up
  • 3. introduction hello http api! hello okhttp! uh oh.. scale! hello http/2! wrapping up
  • 4. * Can be blamed for the http/2 defects in okhttp! @adrianfcole • engineer at Pivotal on Spring Cloud • lots of open source work • focus on cloud computing
  • 5. okhttp • HttpURLConnection Apache HttpClient compatible • designed for java and android • BDFL: Jesse Wilson from square https://github.com/square/okhttp
  • 6. introduction hello http api! hello okhttp! uh oh.. scale! hello http/2! wrapping up
  • 7. $ curl https://apihost/things -H ‘SecurityToken: b08c85073c1a2d02’ -H ‘Accept: application/json’ [ { "id": 1, "owner_id": 0, "name": "Able" }, ... { "id": 26, "owner_id": 0, $ curl https://apihost/things/2 -H ‘SecurityToken: b08c85073c1a2d02’ -H ‘Accept: application/json’ { "id": 2, "owner_id": 0, "name": "Beatific" } $ curl -X POST https://apihost/things -H ‘SecurityToken: b08c85073c1a2d02’ -H ‘Content-Type: application/json’ -d ’{ "name": "Open-minded" }’ $ curl -X DELETE https://apihost/things/2 -H ‘SecurityToken: b08c85073c1a2d02’ json apis are so simple
  • 8. $ curl https://apihost/things -H ‘SecurityToken: b08c85073c1a2d02’ -H ‘Accept: application/json’ [ { "id": 1, "owner_id": 0, "name": "Able" }, ... { "id": 26, "owner_id": 0, "name": "Zest" } $ curl https://apihost/things/2 -H ‘SecurityToken: b08c85073c1a2d02’ -H ‘Accept: application/json’ { "id": 2, "owner_id": 0, "name": "Beatific" } $ curl -X POST https://apihost/things -H ‘SecurityToken: b08c85073c1a2d02’ -H ‘Content-Type: application/json’ -d ’{ "name": "Open-minded" }’ $ curl -X DELETE https://apihost/things/2 -H ‘SecurityToken: b08c85073c1a2d02’ so many bytes?! 1642!
  • 9. $ curl --compress https://apihost/things -H ‘SecurityToken: b08c85073c1a2d02’ -H ‘Accept: application/json’ -H ‘Accept-encoding: gzip, deflate’ [ { "id": 1, "owner_id": 0, "name": "Able" }, ... { "id": 26, "owner_id": 0, "name": "Zest" $ curl https://apihost/things/2 -H ‘SecurityToken: b08c85073c1a2d02’ -H ‘Accept: application/json’ { "id": 2, "owner_id": 0, "name": "Beatific" } $ curl -X POST https://apihost/things -H ‘SecurityToken: b08c85073c1a2d02’ -H ‘Content-Type: application/json’ -d ’{ "name": "Open-minded" }’ $ curl -X DELETE https://apihost/things/2 -H ‘SecurityToken: b08c85073c1a2d02’ now with gzip 318
  • 10. java + gson url = new URL(“https://apihost/things”); connection = (HttpURLConnection) url.openConnection(); connection.setRequestProperty(“SecurityToken”, “b08c85073c1a2d02”); connection.setRequestProperty(“Accept”, “application/json”); connection.setRequestProperty(“Accept-Encoding”, "gzip, deflate"); is = connection.getInputStream(); isr = new InputStreamReader(new GZIPInputStream(is)); things = new Gson().fromJson(isr, new TypeToken<List<Thing>>(){});
  • 11. okhttp + gson client = new OkHttpClient(); url = new URL(“https://apihost/things”); connection = new OkUrlFactory(client).open(url); connection.setRequestProperty(“SecurityToken”, “b08c85073c1a2d02”); connection.setRequestProperty(“Accept”, “application/json”); connection.setRequestProperty(“Accept-Encoding”, "gzip, deflate"); is = connection.getInputStream(); isr = new InputStreamReader(is); // automatic gunzip things = new Gson().fromJson(isr, new TypeToken<List<Thing>>(){}); is.close();
  • 12. We won! • List body reduced from 1642 to 318 bytes! • We saved some lines using OkHttp • Concession: cpu for compression, curl is a little verbose.
  • 13. introduction hello http api! hello okhttp! uh oh.. scale! hello http/2! wrapping up
  • 14. okhttp • v2.5 has lots of stuff since v1 • buffer, call, cache, interceptor, url • http/2 and WebSocket support • Apache adapter https://github.com/square/okhttp
  • 15. okhttp client = new OkHttpClient(); request = new Request.Builder() .url(“https://apihost/things”) .header(“SecurityToken”, “b08c85073c1a2d02”) .header(“Accept”, “application/json”) .header(“Accept-Encoding”, "gzip, deflate”).build(); // ^^ look, ma.. I’m immutable! reader = client.newCall(request).execute().body().charStream(); things = new Gson().fromJson(reader, new TypeToken<List<Thing>>(){}); • OkHttp has its own api, which has a concise way to get bytes or chars (via okio).
  • 16. okhttp call client = new OkHttpClient(); request = new Request.Builder() .url(“https://apihost/things”) .header(“SecurityToken”, “b08c85073c1a2d02”) .header(“Accept”, “application/json”) .header(“Accept-Encoding”, "gzip, deflate").build(); call = client.newCall(request); call.enqueue(new ParseThingsCallback()); call.cancel(); // changed my mind • OkHttp also has an async api, which (also) supports cancel!
  • 17. • # Explicity trust certs for your properties • new CertificatePinner.Builder() • .add(“my.biz”, publicKeySHA1) • .add(“*.my.biz”, publicKeySHA1) • .build() • # Respond to authentication challenges • new Authenticator() { • public Request authenticate(Proxy p, Response rsp) { • return rsp.request().newBuilder() • .header(“Authorization", “Bearer …”) • # Set your own floor for TLS • new ConnectionSpec.Builder(MODERN_TLS) okhttp security
  • 18. okhttp interceptor client = new OkHttpClient(); client.interceptors().add((chain) ->
 chain.proceed(chain.request().newBuilder()
 .addHeader("SecurityToken", securityToken.get())
 .build())
 ); request = new Request.Builder() .url(“https://apihost/things”) .header(“Accept-Encoding”, "gzip, deflate").build(); call = client.newCall(request); call.enqueue(new ParseThingsCallback()); • Now you can change your security token!
  • 19. okio • ByteString • Unbounded Buffer • Source/Sink abstraction https://github.com/square/okio
  • 20. // Okio is (more than) a prettier DataInputStream BufferedSink sink = Okio.buffer(Okio.sink(file)); sink.writeUtf8("Hello, java.io file!”); sink.writeLong(1000000000000000L); sink.close(); // Streaming writes with no housekeeping new RequestBody() { @Override public void writeTo(BufferedSink sink) throws IOException { sink.writeUtf8("Numbersn"); sink.writeUtf8("-------n"); for (int i = 2; i <= 997; i++) { sink.writeUtf8(String.format(" * %s = %sn", i, factor(i))); } } —snip— // Lazy, composable bodies new MultipartBuilder("123") .addPart(RequestBody.create(MediaType.parse(“text/plain”, "Quick")) .addPart(new StreamingBody("Brown")) okio samples
  • 21. samples • Starters like web crawler • How-to guide w/ recipes https://github.com/square/okhttp/tree/master/samples
  • 22. introduction hello http api! hello okhttp! uh oh.. scale! hello http/2! wrapping up
  • 23. Hey.. List #1 is slow! 368!
  • 24. Ask Ilya why! • TCP connections need 3- way handshake. • TLS requires up to 2 more round-trips. • Read High Performance Browser Networking http://chimera.labs.oreilly.com/books/1230000000545
  • 25. HttpUrlConnection • http.keepAlive - should connections should be pooled at all? Default is true. • http.maxConnections - maximum number of idle connections to each host in the pool. Default is 5. • get[Input|Error]Stream().close() - recycles the connection, if fully read. • disconnect() - removes the connection.
  • 26. Don’t forget to read! ... is = tryGetInputStream(connection); isr = new InputStreamReader(is); things = new Gson().fromJson(isr, new TypeToken<List<Thing>>(){}); ... InputStream tryGetInputStream(HttpUrlConnection connection) throws IOException { try { return connection.getInputStream(); } catch (IOException e) { InputStream err = connection.getErrorStream();   while (in.read() != -1); // skip err.close(); throw e; }
  • 27. or just use okhttp try (ResponseBody body = client.newCall(request).execute().body()) { // connection will be cleaned on close. } client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { // body is implicitly closed on failure } @Override public void onResponse(Response response) { // make sure you call response.body().close() when done } });
  • 28. We won! • Recycled socket requests are much faster and have less impact on the server. • Concessions: must read responses, concurrency is still bounded by sockets.
  • 29. Let’s make List #2 free Cache-Control: private, max-age=60, s-maxage=0 Vary: SecurityToken Step 1: add a little magic to your server response Step 2: make sure you are using a cache! client.setCache(new Cache(dir, 10_MB)); Step 3: pray your developers don’t get clever // TODO: stupid server sends stale data without this new Request.Builder().url(”https://apihost/things?time=” + currentTimeMillis());
  • 30. // Limit cache duration thisMessageWillSelfDestruct = new Request.Builder() .url(“https://foo.com/weather”) .cacheControl(new CacheControl.Builder().maxAge(12, HOURS).build()) .build(); // Opt-out of response caching notStored = new Request.Builder() .url(“https://foo.com/private”) .cacheControl(CacheControl.FORCE_NETWORK) .build(); // Offline mode offline = new Request.Builder() .url(“https://foo.com/image”) .cacheControl(CacheControl.FORCE_CACHE) .build(); okhttp cache recipes
  • 31. We won again! • No time or bandwidth used for cached responses • No application-specific cache bugs code. • Concessions: only supports “safe methods”, caching needs to be tuned.
  • 32. introduction hello http api! hello okhttp! uh oh.. scale! hello http/2! wrapping up
  • 33. http/1.1 • rfc2616 - June 1999 • text-based framing • defined semantics of the web http://www.w3.org/Protocols/rfc2616/rfc2616.html
  • 34. FYI: RFC 2616 is dead! • RFC 7230-5 replaces RFC 2616. • Checkout details on www.mnot.net/blog
  • 35. spdy/3.1 http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1 • google - Sep 2013 • binary framing • retains http/1.1 semantics • concurrent multiplexed streams
  • 36. http/2 https://tools.ietf.org/html/rfc7540 • rfc7540 - May 2015 • binary framing • retains http/1.1 semantics • concurrent multiplexed streams
  • 39. Looking at the whole message Request: request line, headers, and body Response: status line, headers, and body
  • 40. http/1.1 round-trip GZIPPED DATA Content-Length: 318 Cache-Control: private, max-age=60, s- maxage=0 Vary: SecurityToken Date: Sun, 02 Feb 2014 20:30:38 GMT Content-Type: application/json Content-Encoding: gzip Host: apihost SecurityToken: b08c85073c1a2d02 Accept: application/json Accept-encoding: gzip, deflate GET /things HTTP/1.1 HTTP/1.1 200 OK • http/1.1 sends requests and responses one at a time over a network connection
  • 41. http/2 round-trip GZIPPED DATA :status: 200 content-length: 318 cache-control: private, max-age=60, s- maxage=0 vary: SecurityToken date: Sun, 02 Feb 2014 20:30:38 GMT content-type: application/json :method: GET :authority: apihost :path: /things securitytoken: b08c85073c1a2d02 accept: application/json accept-encoding: gzip, deflate HEADERS Stream: 3 Flags: END_HEADERS, END_STREAM HEADERS Stream: 3 Flags: END_HEADERS DATA Stream: 3 Flags: END_STREAM • http/2 breaks up messages into stream-scoped frames
  • 42. Interleaving HEADERS Stream: 5 Flags: END_HEADERS, END_STREAM HEADERS Stream: 3 Flags: END_HEADERS DATA Stream: 5 Flags: DATA Stream: 5 Flags: END_STREAM HEADERS Stream: 3 Flags: END_HEADERS, END_STREAM HEADERS Stream: 5 Flags: END_HEADERS DATA Stream: 3 Flags: END_STREAM • http/2 multiplexes a network connection by interleaving request/response frames
  • 43. Canceling a Stream HEADERS Stream: 5 Flags: END_HEADERS, END_STREAM HEADERS Stream: 3 Flags: END_HEADERS DATA Stream: 5 Flags: HEADERS Stream: 3 Flags: END_HEADERS, END_STREAM HEADERS Stream: 5 Flags: END_HEADERS DATA Stream: 3 Flags: END_STREAM RST_STREAM Stream: 5 ErrorCode: CANCEL • interrupts a response without affecting the connection
  • 44. control frames HEADERS Stream: 5 HEADERS Stream: 3 DATA Stream: 5 DATA Stream: 3 HEADERS Stream: 3 HEADERS Stream: 5 SETTINGS Stream: 0 SETTINGS Stream: 0 DATA Stream: 5 • connection-scoped frames allow runtime updates, like flow-control
  • 47. http/1.1 headers GZIPPED DATA Content-Length: 318 Cache-Control: private, max-age=60, s- maxage=0 Vary: SecurityToken Date: Sun, 02 Feb 2014 20:30:38 GMT Content-Type: application/json Content-Encoding: gzip Host: apihost SecurityToken: b08c85073c1a2d02 Accept: application/json Accept-encoding: gzip, deflate GET /things HTTP/1.1 HTTP/1.1 200 OK 168! 195! 318 • You can gzip data, but not headers!
  • 48. header compression GZIPPED DATA :status: 200 content-length: 318 cache-control: private, max-age=60, s-maxage=0 vary: SecurityToken date: Sun, 02 Feb 2014 20:30:38 GMT content-type: application/json content-encoding: gzip :method: GET :authority: apihost :path: /things securitytoken: b08c85073c1a2d02 accept: application/json accept-encoding: gzip, deflate HEADERS Stream: 3 Flags: END_HEADERS, END_STREAM HEADERS Stream: 3 Flags: END_HEADERS DATA Stream: 3 Flags: END_STREAM 8 bytes 52 bytes compressed 8 bytes 85 bytes compressed • 161 byte overhead instead of 363 8 bytes
  • 49. indexed headers! GZIPPED DATA :status: 200 content-length: 318 cache-control: private, max-age=60, s-maxage=0 vary: SecurityToken date: Sun, 02 Feb 2014 20:30:39 GMT content-type: application/json content-encoding: gzip :method: GET :authority: apihost :path: /things securitytoken: b08c85073c1a2d02 accept: application/json accept-encoding: gzip, deflate HEADERS Stream: 3 Flags: END_HEADERS, END_STREAM HEADERS Stream: 3 Flags: END_HEADERS DATA Stream: 3 Flags: END_STREAM 8 bytes 28 bytes compressed 8 bytes 30 bytes compressed • 82 byte overhead instead of 363 8 bytes
  • 50. hpack http://tools.ietf.org/html/rfc7541 • rfc7540 - May 2015 • static and dynamic table • huffman encoding
  • 52. push promise :method: GET :path: /things ... HEADERS Stream: 3 HEADERS Stream: 3 DATA Stream: 4 :method: GET :path: /users/0 ... PUSH_PROMISE Stream: 3 Promised-Stream: 4 HEADERS Stream: 4 push response goes into cache DATA Stream: 3 Server guesses a future request or indicates a cache invalidation
  • 53. okhttp + http/2 • OkHttp 2.3+ supports http/2 on TLS+ALPN connections. • Works out of the box on Android • Java needs hacks until JEP 244 For now, add jetty’s ALPN to your bootclasspath. * Verify version matches your JRE * $ java -Xbootclasspath/p:/path/to/alpn-boot-8.1.4.v20150727.jar
  • 54. We won! • 1 socket for 100+ concurrent streams. • Advanced features like flow control, cancellation and cache push. • Dramatically less header overhead.
  • 55. okhttp tools • There are tools that leverage OkHttp natively… • including its http/2 features.
  • 56. MockWebServer SSLSocketFactory factory = SslContextBuilder.localhost().getSocketFactory(); OkHttpClient client = new OkHttpClient() .setSslSocketFactory(factory); @Rule public final MockWebServer server = new MockWebServer() .setSslSocketFactory(factory); @Test public void evenWithHttp2SlowResponsesKill() throws Exception { server.enqueue(new MockResponse().setBody(lotsOfThings) .throttleBody(1024, 1, SECONDS)); // slow connection 1KiB/second request = new Request.Builder() .url(server.getUrl(”/”) + ”things”) —snip— • MockWebServer uses http/2 by default when using TLS
  • 57. Retrofit 2 @Headers("Accept-Encoding: gzip, deflate”) interface ThingService { @GET("things") Single<List<Things> list(); // RxJava support! } retrofit = new Retrofit.Builder() .client(client) .baseUrl(“https://apihost/“) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build(); thingsService = retrofit.create(ThingService.class); subscription = thingsService.iist().subscribe(System.out::println) • Retrofit 2 extends OkHttp with api model binding
  • 58. okcurl $ java -Xbootclasspath/p:alpn-boot.jar -jar okcurl.jar https://twitter.com -X HEAD --frames >> CONNECTION 505249202a20485454502f322e300d0a0d0a534d0d0a0d0a << 0x00000000 6 SETTINGS >> 0x00000000 6 SETTINGS >> 0x00000000 4 WINDOW_UPDATE >> 0x00000000 0 SETTINGS ACK >> 0x00000003 60 HEADERS END_STREAM|END_HEADERS << 0x00000000 0 SETTINGS ACK << 0x00000003 2097 HEADERS END_STREAM|END_HEADERS >> 0x00000000 8 GOAWAY
  • 59. introduction hello http api! hello okhttp! uh oh.. scale! hello http/2! wrapping up
  • 60. Engage! • Consider http/2 or at least spdy! • Check-out okhttp and friends • Test http/2 load balancers like google cloud https://github.com/square/okhttp/tree/master/mockwebserver http://square.github.io/retrofit/ https://cloud.google.com/compute/docs/load-balancing/http/