APIM – Caching Responses

Posted: May 10, 2020  |  Categories: Azure
#1 Azure Monitoring Platform

This blog shows one simple way to cache an image response using Azure API Management. This is the last blog in this series. See here for the previous blog. Microsft states the best practice for caching here. I am going to present a new solution that retrieves images that are almost static. They change on at least a monthly cadence.

Caching Responses in APIM

GetImages V2

I use an improved version of the solution in the last blog to exhibit this feature of APIM. In the beginning the images we want to retrieve are in a SQL database inside a VNet. In the first step Azure Data factory extracts these images and writes them to a Blob Storage outside the VNet. I am not going to talk about the data factory here but you can look up this this Microsoft article to see how to do it.

The APIM has the same front end as in previous blogs. This time the back end calls Logic App to retrieve the image from Blob Storage. The Logic App runs are reduced to a minimum by caching the the image response.

Before talking about the new APIM policy let’s examine the Logic App design briefly. This is unremarkable and starts via a HTTP trigger. In a first Get Blob Content Action the path is constructed using the productCode and site sent by the caller. Finally the second action returns the image.

Returning now to the main topic of the blog, a caching policy. The policy starts with assigning the productCode or Site from the header or a query parameter in the incoming call. Secondly the body for the subsequent POST to the logic app is created using a liquid template.

Thirdly the productCode and site are assigned to custom headers for the Logic App request. This step is required because we want to cache the image by custom header values sent to the Logic App. The Logic App just ignores these headers but the cache does not. The cache lookup is set on these header values. I think this is much simpler to set up than the custom caching in my previous blog. If the cache hit occurs the response is returned without calling the Logic App.

<-- Set up the cache lookup -->
        <cache-lookup vary-by-developer="false" vary-by-developer-groups="false" downstream-caching-type="none">
            <vary-by-header>Product-Code</vary-by-header>
            <vary-by-header>Site</vary-by-header>
        </cache-lookup>

If there is no cache hit the Logic App is called from the backend and an image returns in the response.

Finally the caching the response for 60 minutes before the image is returns to the caller.

   <outbound>
        <base />
<-- Store the response in the cache  -->
        <cache-store duration="3600" />
    </outbound>

The full policy is below.

<policies>
    <inbound>
        <!--
        Get site from headers or query string
        -->
        <set-variable name="site-id" value="@(context.Request.Url.Query.GetValueOrDefault("site"))" />
        <choose>
            <when condition="@(context.Request.Headers.GetValueOrDefault("Site") != null)">
                <set-variable name="site-id" value="@(context.Request.Headers.GetValueOrDefault("Site"))" />
            </when>
        </choose>
        <base />
        <set-body template="liquid">
                {
                    "productCode": "{{context.Request.MatchedParameters["productCode"]}}",
                    "site": "{{context.Variables["site-id"]}}"
                }
                </set-body>
        <set-header name="Content-Type" exists-action="override">
            <value>application/json</value>
        </set-header>
        <set-header name="Product-Code" exists-action="override">
            <value>@((string)context.Request.MatchedParameters["productCode"])</value>
        </set-header>
        <set-header name="Site" exists-action="override">
            <value>@((string)context.Variables["site-id"])</value>
        </set-header>
<-- Set up the cache lookup -->
        <cache-lookup vary-by-developer="false" vary-by-developer-groups="false" downstream-caching-type="none">
            <vary-by-header>Product-Code</vary-by-header>
            <vary-by-header>Site</vary-by-header>
        </cache-lookup>

        <!-- PARAMETERIZATION Required -->
        <set-backend-service id="apim-generated-policy" backend-id="LogicApp_is-get-image-dev-la_is-dev-rg_<guid>" />
        <set-method id="apim-generated-policy">POST</set-method>
        <rewrite-uri id="apim-generated-policy" template="/request/paths/invoke/?api-version=2016-06-01&amp;sp=/triggers/request/run&amp;sv=1.0&amp;sig={{product-images_getimages-for-apim-user_<guid>}}" />
        <set-header id="apim-generated-policy" name="Ocp-Apim-Subscription-Key" exists-action="delete" />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />

<-- Store the response in the cache  -->
        <cache-store duration="3600" />

    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

#1 Azure Monitoring Platform

Conclusion

Caching of an image was set up by using a cache lookup is based on header values sent to a logic app. This works well and reduces the number of times the Logic App is run. Using Redis an external cache is shown in the solution because the cache may grow quite large. You can add this to the policy but is not shown here. Please consult he Microsoft documentaion to find out how this is done. This ends my learning about APIM policies.

Explore more on Secure Azure Functions Using API Management

turbo360

Back to Top