Today I’m going to talk about how you can create an omnichannel service that support a cool part of the HTTP standard called Conditional GETs. This feature is especially important for mobile solutions as it will save bandwidth and improve performance on both the client and server.
In this example, I will use PHP and build on the service I created in a previous video, but the same functionality can be achieved on all major platforms, like any Java variation and .NET.
Let’s start with some theory. The basic idea is that the first call to the server is made as usual, and the response from the service include the requested data and a normal “OK” (200) HTTP response code. It also includes two specific headers, one with a date indicating when the resource was last changed, and the other with a unique identifier for the current version of the resource, called etag (entity tag). In the next request, the client will supply these two values, and this time the response depends on whether the resource has changed or not. If the resource was changed, the response format will be the same as the first response, but if the resource was not changed, only the “Not Modified” (304) HTTP response code is returned. This very quick response (only the HTTP headers are transferred in either direction) tells the client that the previously retrieved data is still valid.
Now it’s time to create a service that does this…
$xml_source = file_get_contents("http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/ws/RSS/topfreeapplications/limit=50/xml");
$xml = simplexml_load_string($xml_source);
$last_modified = gmdate("D, d M Y H:i:s \G\M\T", strtotime($xml->updated));
$etag = '"'.md5($last_modified).'"';
$if_modified_since = isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]) ? $_SERVER["HTTP_IF_MODIFIED_SINCE"] : false;
$if_none_match = isset($_SERVER["HTTP_IF_NONE_MATCH"]) ? $_SERVER["HTTP_IF_NONE_MATCH"] : false;
if(($if_none_match && $if_none_match == $etag) || ($if_modified_since && strtotime($if_modified_since) >= strtotime($last_modified)))
header("HTTP/1.1 304 Not Modified");
$im_namespace = "http://itunes.apple.com/rss";
$apps = array();
$index = 0;
foreach($xml->entry as $entry)
$app = array();
$app[id] = $index;
$app[title] = (string)$entry->children($im_namespace)->name;
$app[developer] = (string)$entry->children($im_namespace)->artist;
foreach($entry->children($im_namespace)->image as $image)
$app[image . $image->attributes()->height] = (string)$image;
$apps = $app;
$response[apps] = $apps;
…and just as in the original code (from the previous video), we start by getting the XML (line 2-3). Then we set the default time zone to GMT (line 4) and get the date when the feed was last changed from the XML (line 5). We create an etag by making an MD5 hash from that date (line 6) and set the two headers (line 7-8). Then we get the two headers (if they are present) from the request (line 9-10), and check whether the version that the client has is old or still valid (line 11). If it’s still valid, we simply return the 304 status (line 13) and if not, se parse the XML as in the original code.
To put this code on your server (using Coda 2), I just create a new file named getConditional.php, paste the code we just walked through, save it, and then it can be called with (replace 0.0.0.0 with the IP of your server):
The nice thing when building apps is that most reusable libraries, like AFNetworking, has built-in support for conditional GETs, so there’s actually no coding required to make use of this in an app.
There you have an omnichannel service that support conditional GETs and that can be easily consumed by your apps or webs.