Kenichiro Nakamura
Posted on October 20, 2021
We can use rate-limit
policies of Azure API Management to throttle API calls. See Advanced request throttling with Azure API Management for more detail.
In this article, I explain how we can customize the response message.
Default behavior
This is a sample policy which limits up to 5 calls per a minute.
<policies>
<inbound>
<rate-limit calls="5" renewal-period="60" />
<base />
<mock-response status-code="200" content-type="application/json" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
</policies>
If we send 6th request in a minute, we can see the following message back from the service.
Change Response Header
rate-limit
policy has many attributes to customize the behavior. See here for the list.
For example, we can add remaining-calls-header-name
to let caller know how many more calls then can send before they get throttled. Following policy will add additional response header to include the number.
<rate-limit calls="5" renewal-period="60" remaining-calls-header-name="RemainingCalls"/>
And this is the response header on my first call, which let me know I can do four more calls before throttled.
Following policy adds total calls number in response header.
<rate-limit calls="5" renewal-period="60" remaining-calls-header-name="RemainingCalls" total-calls-header-name="TotalCalls" />
Customize the response
If we want to change the response message from default one, we can use on-error
policy. We can use on-error policy to control error behavior, including 429 too many requests.
Simple example
This policy overrides behavior for RateLimitExceeded error. It still returns 429 status code, but message body is overwritten.
<policies>
<inbound>
<rate-limit calls="5" renewal-period="60" remaining-calls-header-name="RemainingCalls" total-calls-header-name="TotalCalls" />
<base />
<mock-response status-code="200" content-type="application/json" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<choose>
<when condition="@(context.LastError.Reason == "RateLimitExceeded")">
<return-response>
<set-status code="429" />
<set-header name="Content-Type" exists-action="override">
<value>application/json</value>
</set-header>
<set-body>{
"Don't call anymore"
}</set-body>
</return-response>
</when>
</choose>
<base />
</on-error>
</policies>
The response I see after 6th call is this.
Use LastError context
APIM provide error detail in context.LastError which we can use to enrich the message. Following example append error message to previous custom message.
<policies>
<inbound>
<rate-limit calls="5" renewal-period="60" remaining-calls-header-name="RemainingCalls" total-calls-header-name="TotalCalls" />
<base />
<mock-response status-code="200" content-type="application/json" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<choose>
<when condition="@(context.LastError.Reason == "RateLimitExceeded")">
<return-response>
<set-status code="429" />
<set-header name="Content-Type" exists-action="override">
<value>application/json</value>
</set-header>
<set-body>@{
return String.Format("Don't call anymore because you get {0}",
context.LastError.Message);
}</set-body>
</return-response>
</when>
</choose>
<base />
</on-error>
</policies>
The result looks like below.
Summary
I explain how we can use on-error
to control error behavior. If you are interested in more detail about policy expression, see API Management policy expressions.
Posted on October 20, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.