MOBILE API AND
CACHING
Making the most of your APIs
PERFORMANCE
MATTERS.
MOBILE APPLICATION

AVERAGE API RESPONSE TIME.
1.24seconds
source: New Relic
TIME SPENT.
SERVER
20%
NETWORK
80%
BASIC MATHEMATICS.
session duration
request duration = requests
per session
WILDLY INACCURATE TESTS.
Check my balance

43 requests in 70 seconds
Check-in

46 requests in 30 seconds
Open a message

24 requests in 40 seconds
AVERAGE:
0.92second
THE HARD STUFF.
•INCREASE SESSION TIME.
•REDUCE REQUEST TIME.
DOING MORE.
session duration
request duration = requests
per session
MAKE FEWER 

REQUESTS
PER ACTION.
BE SPECIFIC.
WEB BROWSER 

CACHES EVERYTHING

UNLESS TOLD
OTHERWISE.
MOBILE APPLICATION

CACHES NOTHING

UNLESS TOLD
OTHERWISE.
BASIC REQUIREMENT.
ONE =object
ONE
URI
FOLLOWING JSON API
GUIDELINES HELPS ENSURE
OBJECT TO URI EQUIVALENCY.
http://jsonapi.org
HTTP, FOR YOU 

IT WORKS.
GET /collections/12 HTTP/1.1
Host: flipbit.dev
!
HTTP/1.1 200 OK
Date: Thu, 17 Oct 2013 01:42:00 GMT
Accept-Ranges: bytes
Content-Type: application/vnd.api+json
Content-Length: 42
Connection: keep-alive
Location: http://flipbit.dev/collections/12
GET /collections/12 HTTP/1.1
Host: flipbit.dev
!
HTTP/1.1 200 OK
Date: Thu, 17 Oct 2013 01:42:00 GMT
Last-Modified: Thu, 17 Oct 2013 01:38:57 GMT
ETag: "b79f914dde3ab5e3095372de46591b46"
Expires: Thu, 24 Oct 2013 01:38:57 GMT
Cache-Control: max-age=604800, private
Accept-Ranges: bytes
Content-Type: application/vnd.api+json
Content-Length: 42
Connection: keep-alive
Location: http://flipbit.dev/collections/12
GET /collections/12 HTTP/1.1
Host: flipbit.dev
If-Modified-Since: Thu, 10 Oct 2013 20:14:48 GMT
If-None-Match: "a1846ac92492d2347c6235b4d2611184"
!
HTTP/1.1 200 OK
Date: Thu, 17 Oct 2013 01:42:00 GMT
Last-Modified: Thu, 17 Oct 2013 01:38:57 GMT
ETag: "b79f914dde3ab5e3095372de46591b46"
Expires: Thu, 24 Oct 2013 01:38:57 GMT
Cache-Control: max-age=604800, private
Accept-Ranges: bytes
Content-Type: application/vnd.api+json
Content-Length: 42
Connection: keep-alive
Location: http://flipbit.dev/collections/12
CACHE-CONTROL 

ON AMAZON S3.
GET /buket.mycompany.com/welcome.json HTTP/1.1
Host: s3.amazonaws.com
!
HTTP/1.1 200 OK
x-amz-id-2: UleVE3wbOPZa2EW+RpWj834yy5OOMLNmi/w…
x-amz-request-id: 4ADBB2EBF80F5D46
Date: Thu, 17 Oct 2013 01:42:00 GMT
Last-Modified: Thu, 17 Oct 2013 01:38:57 GMT
ETag: "b79f914dde3ab5e3095372de46591b46"
Accept-Ranges: bytes
Content-Type: application/octet-stream
Content-Length: 23
Connection: keep-alive
Server: AmazonS3
GET /buket.mycompany.com/welcome.json HTTP/1.1
Host: s3.amazonaws.com
!
HTTP/1.1 200 OK
x-amz-id-2: UleVE3wbOPZa2EW+RpWj834yy5OOMLNmi/w…
x-amz-request-id: 4ADBB2EBF80F5D46
Date: Thu, 17 Oct 2013 01:42:00 GMT
Last-Modified: Thu, 17 Oct 2013 01:38:57 GMT
ETag: “b79f914dde3ab5e3095372de46591b46"
Cache-Control: ???
Expires: ???
Accept-Ranges: bytes
Content-Type: application/octet-stream
Content-Length: 23
Connection: keep-alive
Server: AmazonS3
CACHING IS UNCERTAIN.
•There’s no cache-control header so it’s left to the
client to decide.
•iOS most likely will cache between 6 hours and 1 day
and will always revalidate.
•Android it depends, but most likely won’t cache.
DON’T LET THE CLIENT DECIDE.
•Add the x-amz-meta-Cache-Control header when
doing a PUT to S3.
•It’s recommended to use a max-age of at least one
month.
•Don’t use x-amz-meta-Expires. 

The object will not be cached after its expiry date.
CACHE-CONTROL 

WITH RUBY ON RAILS.
GET /collections/12 HTTP/1.1
Host: app.mycompany.com
!
Cache-Control: max-age=0, private, must-revalidate
Content-Type: application/json; charset=utf-8
ETag: "4a200c9d8fb14925e7461d63b59f4e82"
Server: nginx/1.2.3 + Phusion Passenger 3.0.17
(mod_rails/mod_rack)
Set-Cookie: request_method=GET; path=/
Status: 200
Content-Length: 144
Connection: Close
FIXING CACHE-CONTROL.
class FlipsController < ApplicationController
respond_to :json
!
def index
# ...
!
# Last-Modified and ETag
flipbit_etag = Digest::MD5.digest(@flipbit.to_s).to_s
fresh_when last_modified: DateTime.now, etag: flipbit_etag
!
# Cache-Control
expires_in 3.day, :must_revalidate => false, :public => true
# ...
end
end
GET /collections/12 HTTP/1.1
Host: app.mycompany.com
!
Cache-Control: max-age=86400, public
Content-Type: application/json; charset=utf-8
ETag: "4a200c9d8fb14925e7461d63b59f4e82"
Server: nginx/1.2.3 + Phusion Passenger 3.0.17
(mod_rails/mod_rack)
Set-Cookie: request_method=GET; path=/
Status: 200
Content-Length: 144
Connection: Close
CACHING IS BETTER.
•iOS will honour the cache-control header as long as
there’s cache space.
•Android apache’s HttpClient does not handle
caching, android-query does.
CACHING ON 

THE DEVICE.
NEVER HARD CODE
CACHE LOGIC.
MAKE SURE YOU HAVE
ENOUGH STORAGE.
CACHE ON iOS.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSUInteger mb = 1024*1024;
!
// Configure NSURLCache with larger storage
[NSURLCache setSharedURLCache:
[[NSURLCache alloc] initWithMemoryCapacity:(50*mb)
diskCapacity:(100*mb)
diskPath:nil]
];
!
// ...
// ...
return YES;
}
MAKE EVERY 

ROUND-TRIP COUNT.
BONUS MATERIAL.
Amazon S3 performance.
S3 GET PERFORMANCE.
•Make sure you set your Cache-Control headers
using x-amz-meta-Cache-Control.
•Intensive objects benefit from CloudFront by a
factor of 2 or more.
S3 PUT PERFORMANCE.
•Avoid sequential keys. S3 stores key names in
alphabetical order; key name dictates which
partition the key is stored in.





http://bit.ly/s3performance
AVOID DATES AS PREFIX.
examplebucket/2013-26-05-15-00-00/cust1234234/photo1.jpg
examplebucket/2013-26-05-15-00-00/cust3857422/photo2.jpg
examplebucket/2013-26-05-15-00-00/cust1248473/photo2.jpg
examplebucket/2013-26-05-15-00-00/cust8474937/photo2.jpg
examplebucket/2013-26-05-15-00-00/cust1248473/photo3.jpg
...
examplebucket/2013-26-05-15-00-01/cust1248473/photo4.jpg
examplebucket/2013-26-05-15-00-01/cust1248473/photo5.jpg
examplebucket/2013-26-05-15-00-01/cust1248473/photo6.jpg
examplebucket/2013-26-05-15-00-01/cust1248473/photo7.jpg
...
USE HASH AS PREFIX.
examplebucket/232a-2013-26-05-15-00-00/cust1234234/photo1.jpg
examplebucket/7b54-2013-26-05-15-00-00/cust3857422/photo2.jpg
examplebucket/921c-2013-26-05-15-00-00/cust1248473/photo2.jpg
examplebucket/ba65-2013-26-05-15-00-00/cust8474937/photo2.jpg
examplebucket/8761-2013-26-05-15-00-00/cust1248473/photo3.jpg
examplebucket/2e4f-2013-26-05-15-00-01/cust1248473/photo4.jpg
examplebucket/9810-2013-26-05-15-00-01/cust1248473/photo5.jpg
examplebucket/7e34-2013-26-05-15-00-01/cust1248473/photo6.jpg
examplebucket/c34a-2013-26-05-15-00-01/cust1248473/photo7.jpg
...
SHARING A BUCKET?
examplebucket/my_beautiful_app/40434b70/avatar.jpg
examplebucket/my_beautiful_app/4ee66b70/avatar.jpg
examplebucket/my_beautiful_app/753da383/avatar.jpg
examplebucket/my_beautiful_app/91255df0/avatar.jpg
examplebucket/my_beautiful_app/98e26030/avatar.jpg
examplebucket/my_very_nice_app/a2cb3fdb/video.mpg
examplebucket/my_very_nice_app/cf763412/video.mpg
examplebucket/my_very_nice_app/d6e93451/video.mpg
examplebucket/my_very_nice_app/e68f7670/video.mpg
...
USE SHORT FIXED PREFIX!
examplebucket/mba/40434b70/avatar.jpg
examplebucket/mba/4ee66b70/avatar.jpg
examplebucket/mba/753da383/avatar.jpg
examplebucket/mba/91255df0/avatar.jpg
examplebucket/mba/98e26030/avatar.jpg
examplebucket/mvna/a2cb3fdb/video.mpg
examplebucket/mvna/cf763412/video.mpg
examplebucket/mvna/d6e93451/video.mpg
examplebucket/mvna/e68f7670/video.mpg
...
Mobile Api and Caching

Mobile Api and Caching