. . .

How we save bandwidth when using ApiOmat

In this article I want to write about how we at ApiOmat solve the problem of transferring unnecessary data between clients and server. In app development it's important to think about this because of limited data flatrates and "white" areas with no network connection.

To minimize transferred data our REST interface and our mobile client SDKs support both the HTTP header If-Modified-Since and If-None-Match. How this works is described below.

If-Modified-Since

On a GET request the client send an additional If-Modified-Since header with a timestamp as value. The server can react with the 2 following possibilities:

  1. Server responds with response-code 200, a Modified-Since Header and the data in the body

  2. The response-code from server is 304 and the body is empty

The second case will happen if the requested data on the server was not modified since the given time stamp. At ApiOmat this works for GET requests on single objects. The following cURL example will explain it (for simplification we use -I option to send a HEAD request and get only HTTP headers back):

$ curl -I https://apiomat.org/yambas/rest/apps/TaskManager/models/TaskManagerMain/Task/51482cbae4b0891c605f4099 \
-u __user_creds__ -H "Accept: application/json" -H "X-apiomat-apikey: __key__"
 
HTTP/1.1 200 OK
Date: Tue, 19 Mar 2013 09:21:07 GMT
Last-Modified: 19 Mar 13 10:18:33:629 CET
Content-Type: application/json
Vary: Accept-Encoding
Content-Length: 0
Server: Jetty(7.6.9.v20130131)
 
#Send same request again with If-Modified-Since Header and value from Modified-Since Response
$ curl -I https://apiomat.org/yambas/rest/apps/TaskManager/models/TaskManagerMain/Task/51482cbae4b0891c605f4099 \
-u __user_creds__ -H "Accept: application/json" -H "X-apiomat-apikey: __key__" \
-H 'If-Modified-Since: 19 Mar 13 10:18:33:629 CET'
 
HTTP/1.1 304 Not Modified
Date: Tue, 19 Mar 2013 09:23:04 GMT
Vary: Accept-Encoding
Server: Jetty(7.6.9.v20130131)
 
#HTTP Response-Code is 304

Possible values for If-Modified-Since Header


The HTTP standard specifies that timestamp should be sent according to RFC 1123 standard. But this format only takes care on second. This is not enough for request against ApiOmat REST interface, so we accept only following format which includes also milliseconds:

dd MMM yy HH:mm:ss:SS CET


An example follows:

19 Mar 13 10:18:33:629 CET

Etag/If-None-Match Header

How you can check if a list of objects has changed? If you send an If-None-Match header with your GET request on a list then the server answer with one of the two following possibilities:

  1. Returns the data, response-code 200 and an ETag header

  2. Returns 304 as response-code and NO data if data hash is equal (and so not modified) to sent If-None-Match header value

#Get list of task models
$ curl -v https://apiomat.org/yambas/rest/apps/TaskManager/models/TaskManagerMain/Task/ \
-u __user_creds__ -H "Accept: application/json" -H "X-apiomat-apikey: __key__
 
HTTP/1.1 200 OK
Date: Tue, 19 Mar 2013 09:32:29 GMT
ETag: "1-2114886209"
Content-Type: application/json
Vary: Accept-Encoding
Transfer-Encoding: chunked
Server: Jetty(7.6.9.v20130131)
 
#send request again with If-None-Match header and ETag value from previous HTTP response
$ curl -v https://apiomat.org/yambas/rest/apps/TaskManager/models/TaskManagerMain/Task/ \
-u __user_creds__ -H "Accept: application/json" -H "X-apiomat-apikey: __key__ \
-H "If-None-Match: 1-2114886209"
 
HTTP/1.1 304 Not Modified
Date: Tue, 19 Mar 2013 09:38:08 GMT
Vary: Accept-Encoding
Server: Jetty(7.6.9.v20130131)
...
#HTTP Response-Code ist 304

Support caching in client SDKs

If you use our iOS, Java or Android SDK then all is prepared to save bandwidth, cause we sent the previous explained headers already. A local cache keeps all returned data and return this values if response-code from server is equal to 304.

If you want to disable caching explicit, then you have to call following method for iOS:

[DataStore setCachingStrategy:AOM_NO_CACHE];

For Android and Java the method call equals to:

Datastore.setCachingStrategy( Datastore.AOMCacheStrategy.NO_CACHE );

As you can see we take care of your limited data flatrates and the "white" areas of no network connection.

* link only available in Enterprise Documentation