Bypassing cache in APIm

The good thing about caching

One very strong feature of Azure API manager is the ability to cache data. When implemented, the response is picked up from an in-memory store and returned to the caller within milliseconds. It all depends on the type of data returned, but not all data needs to be kept fresh from the backend systems all the time.

The response to creating an order might be a bad idea to cache, but a list of the company offices might be a good candidate.

There are a million articles on how to implement caching in APIm including the official documentation.

Here is an example that stores a response for an hour, with a separate cache for each developer/caller.

<policies>
    <inbound>
        <base />
        <cache-lookup vary-by-developer="true" vary-by-developer-groups="false" />
    </inbound>
    <outbound>
        <base />
          <cache-store duration="3600" />
    </outbound>
</policies>

The trouble with caching

In some cases you need to force the call to get data from the backend system and not use the cache. One such case is during development of the backend system. If something is updated, the data is not updated until the cache has timed out, and you need that new data now!

I did not find any ready made examples of how to achieve this and that is why I wrote this post.

How to control the cache

The official documentation points to using a header called Cache Control. More information can be found here. In fact, if you test your API from the portal, the tester always sets this header to no-store, no-cache. It is up to you how to handle this header in your API.

Example of no-cache

This is what I did to implement the following case: “If someone sends a Cache Control header with no-cache, you should get the data from the backend system and ignore the cache.”

Using the same example from above, I added some conditions.

<policies>
    <inbound>
        <base />
        <choose>
            <when condition="@(context.Request.Headers.GetValueOrDefault("Cache-Control","").Contains("no-cache") == false)">
                <cache-lookup vary-by-developer="true" vary-by-developer-groups="false" />
            </when>
        </choose>
        <!-- Call your backend service here -->
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
        <choose>
            <when condition="@(context.Request.Headers.GetValueOrDefault("Cache-Control","").Contains("no-cache") == false)">
                <cache-store duration="3600" />
            </when>
        </choose>
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

It is very straight forward: Find a header, and if it does not contain no-cache; use the cache.
If the cache is used the call will be done on row 6 and then go down to row 17, returning what ever is in store.