Using Caching Policy with Azure API Management
This is part-03 of API management policy configuration.
Welcome back to part-03 of Azure API management policy discussion, In the previous 2 blogs we have discussed how to:
- Send Message to Service bus using Azure API Management Policy.
- Read Keyvault secrets using Azure API Management Policy.
In this blog I will continue using part-02 API management and we will discuss to how to use caching policy with azure API management.
In part-02 we are reading the secrets from keyvault and directly sending the secret response back as response using backend policy and this backend policy is configured on our API management operation
if you look at above policy configuration we are using send-request to read the secret from keyvault which is good but what if this API operation is executed 100s of time in a second, this API policy will hit keyvault 100s of time in each operation call keyvault will hit and it might possible that you will get HTTP response code 429, which too many request as the Keyvault has limit to access to secrets number of time, as we know secret usually do not change every second so it does not make sense to make call the keyvault secret on every API call, so it is better to store the secret into somewhere in cache.
Okay, we want to store the secret into the cache but where in the cache?, well thankfully API management has the option to store the keyvault.
You can define the Cache policy here in the API management as Inbound policy, here the template of cache policy
<cache-lookup vary-by-developer="true | false" vary-by-developer-groups="true | false" caching-type="prefer-external | external | internal" downstream-caching-type="none | private | public" must-revalidate="true | false" allow-private-response-caching="@(expression to evaluate)">
<vary-by-header>Accept</vary-by-header>
<!-- should be present in most cases -->
<vary-by-header>Accept-Charset</vary-by-header>
<!-- should be present in most cases -->
<vary-by-header>Authorization</vary-by-header>
<!-- should be present when allow-private-response-caching is "true"-->
<vary-by-header>header name</vary-by-header>
<!-- optional, can repeated several times -->
<vary-by-query-parameter>parameter name</vary-by-query-parameter>
<!-- optional, can repeated several times -->
</cache-lookup>
to read the value from cache in policy
<cache-lookup-value key="cache key value"
default-value="value to use if cache lookup resulted in a miss"
variable-name="name of a variable looked up value is assigned to"
caching-type="prefer-external | external | internal" />
so now we will use the cache-lookup-value policy to read variable from cache and if the value is not available in cache
If you understand the code above we are searching the value from cache and in next line with when block we are checking if the context has variable or not if not then call the keyvault API to read the secret, and store it into cache, the store time duration in this example is defined as 60 seconds.
<cache-store-value key="authUserValue" value="@((string)context.Variables["usernameValue"])" duration="60" />
If now let’s run this configuration and see the result
Its failed 🤔, why??
The similar configuration you can find it in so many blog post so why it’s not working, before explain why, let’s first of all trace the request
If you look at the trace, we are get the value from secret and the secret value is stored into the cache.
At the same time when response body tries to read the value from cache it fails
"The given key was not present in the dictionary.\r\n at System.ThrowHelper.ThrowKeyNotFoundException()\r\n at System.Collections.Generic.Dictionary`2.get_Item(TKey key)"
but why ??, one of the important reason of failure which I got to know after spending a lot of time.
Now I can add a logic here to prevent the failure for the first time.
Now after this change if we test then it will work fine.
If we check the trace the value its reading from cache
Conclusion
Storing value in the cache is always good idea, as it offloads the traffic from your backend and speedup the API response, but at the same time its really important to define the policy with specific order.
I hope you have found this useful.
In the next part we will use the authentication-basic policy with APIM or API calls with basic authentication using azure API Management.
Cheers !! 🍺🍻
You can also refer my YouTube videos on APIM