API Caching

Here at Znode, performance is always at the front of our brains. We sell an eCommerce platform, so the faster it performs, the better the bottom line is for people who build sites on top of it. Performance is basically Feature #1, as literally, every single potential customer asks about it when evaluating our software. And when it came to the Znode API, this was no exception.

Different Customers, Different Uses

We knew early on in the API design process that we were going to implement caching as part of the API, we just weren’t sure exactly what it was going to look like. But what we did know was that it needed to be a completely configurable solution, as every customer will have their own unique requirements for interacting with their eCommerce data. Some customers will want to use sliding cache expirations, while others will require absolute expiration times. Some customers will want to cache their product data for 60 seconds, yet others will cache their products for an hour. And some customers won’t want to cache anything at all. They should all be given the opportunity to handle any of these scenarios, and do so without modifying, recompiling, and redeploying code.

Dial Up, Dial Down

Every customer has their own performance requirements, and giving them configurable cache options allows them to tweak and test until they are satisfied they’ve got the right settings. This flexibility lets customers fiddle with the dials, if you will, and they can do this using a simple configuration file that can be updated on-the-fly.

Cache.config

The solution we came up with is the cache.config file, located in the root of the Znode API. This file provides cache options for every GET endpoint in the API and is automatically tied to the AppDomain, so changes to this file are the same as making changes to the standard web.config file. It’s important to remember that API caching occurs for GET requests only; caching for POST, PUT, and DELETE are not supported (and of course, don’t make much sense). Here’s a snippet of what the cache.config looks like:

<znodeApiCache> <cache enabled="true"> <routes> <!-- Catalog routes --> <route template="catalogs/{catalogId}" enabled="true" sliding="true" duration="60" /> <route template="catalogs" enabled="true" sliding="true" duration="60" /> <!-- Category routes --> <route template="categories/{categoryId}" enabled="true" sliding="true" duration="60" /> <route template="categories" enabled="true" sliding="true" duration="60" /> <route template="categories/catalog/{catalogId}" enabled="true" sliding="true" duration="60" /> <!-- Product routes --> <route template="products/{productId}" enabled="true" sliding="true" duration="60" /> <route template="products/{productId}/{skuId}" enabled="true" sliding="true" duration="60" /> <route template="products" enabled="true" sliding="true" duration="60" /> <route template="products/{productIds}" enabled="true" sliding="true" duration="60" /> <route template="products/catalog/{catalogId}" enabled="true" sliding="true" duration="60" /> <route template="products/category/{categoryId}" enabled="true" sliding="true" duration="60" /> </routes> </cache> </znodeApiCache>

The root <cache> node allows you to enable or disable the entire API caching mechanism. If set to false, then no caching will occur at all for any routes. The <routes> node contains a list of <route> nodes, each with the following attributes:

Attribute Description
template The route template as defined in the \App_Start\WebApiConfig.cs file.
enabled True/false value that determines if caching is enabled for the route (default = true).
sliding True/false value that determines if a sliding cache is used for the route; if false, absolute caching is used (default = true).
duration The number of seconds that the response data for the route should be kept in cache (default = 60 seconds).

Cache Keys And JSON Strings

There are two elements in the cache design that make all this possible: 1. The cache keys for storing data in the cache are the raw URLs of the request, including the entire querystring. A URL maps to a route, thus allowing us to cache data for that route and any parameters it may have, i.e. the querystring. 2. The data stored for each cache key is the raw JSON string returned for the request. Storing the JSON string itself, instead of an object that contains the JSON string, saves a serialization/deserialization trip, which increases performance even further.

Huge Performance Boost

Like any other cache solution, the caching built into the Znode API can provide massive performance gains for your websites and applications and should be utilized as much as possible.