1

I have a use case to use single policy.xml for different environments however the rate-limit is applicable only for certain environment.

For eg:

Dev: rate-limit is applicable (hosted in dev azure subscription)

QA: rate-limit is not applicable (hosted in test azure subscription)

Prod: rate-limit is applicable (hosted in prod azure subscription)

Update: Tried this from one of the posts here post:

    <choose>
        <when condition="@(context.Subscription.Name=="abcd")">
            <rate-limit-by-key calls="1" renewal-period="15" counter-key="@(context.Subscription.Id)" />
        </when>
        <when condition="@(context.Subscription.Name=="efgh")">
            <rate-limit-by-key calls="2" renewal-period="15" counter-key="@(context.Subscription.Id)" />
        </when>
        <otherwise />
    </choose>

Below snippet is from the inbound request and what i don't understand is the value of the first when element condition attribute is false even though it is executed from the "abcd" subscription.

choose (7.565 ms)
    {
    "message": "Expression was successfully evaluated.",
    "expression": "context.Subscription.Name==\"abcd\"",
    "value": false
}
choose (0.251 ms)
    {
    "message": "Expression was successfully evaluated.",
    "expression": "context.Subscription.Name==\"efgh\"",
    "value": false
} 

Solution that worked for me from below approaches:

<choose>
    <when condition="@(context.Request.Url.Host.Contains("dev"))">
        <rate-limit-by-key calls="1" renewal-period="5" counter-key="@(context.Subscription.Id)" />
    </when>
    <when condition="@(context.Request.OriginalUrl.Host.Contains("prod")">
        <rate-limit-by-key calls="2" renewal-period="10" counter-key="@(context.Subscription.Id)" />
    </when>
    <otherwise />
</choose>
Ia1
  • 500
  • 1
  • 7
  • 15
  • I don't think there is a way without adding some clauses – Justin Mathew Feb 13 '22 at 16:34
  • I came across couple of posts here about using clauses but i'm confused with the option counter-key="@(context.Subscription.Id) in the clause whether this is the actual subscription id or the subscription of the API – Ia1 Feb 14 '22 at 15:58
  • Does "different environments" mean different APIM services? – Vitaliy Kurokhtin Feb 14 '22 at 18:55
  • correct.. three apim services – Ia1 Feb 14 '22 at 22:54
  • @la1 counter-key="@(context.Subscription.Id) is basically 3 subscription ids. Which you need to create in all three environments(1 in each). Then the subscription keys should be sent from the clients on request header. If the they hit prod api they should have prod subscription key. Then on APIM we check the subscription in when condition. Check this answer https://stackoverflow.com/a/66379900/8804776 – Justin Mathew Feb 15 '22 at 02:50
  • The alternative solution can be create 3 different products(each for dev, QA and PROD) and add product level rate-limit policy. – Pankaj More Feb 15 '22 at 04:31
  • 1
    I tried the first approach however i'm trying to avoid creating any new product or subscription key because of the business requirement however the second approach is interesting. what is the value that is being passed to Context.Request.OriginalUrl.Host? Is that a developer portal url or the backend-service url or a web service url ? @JustinMathew – Ia1 Feb 15 '22 at 16:10
  • OriginalUrl contains full URL specified with the incoming request. ref : https://github.com/MicrosoftDocs/azure-docs/issues/16317. I have not tested whether it returns www.devenvironment.com or only devenvironment. That you can easily test and figure out – Justin Mathew Feb 15 '22 at 16:12
  • 1
    Got it. thank you and that worked. – Ia1 Feb 15 '22 at 16:23

1 Answers1

2

1.The subscription key based approach is below.

You can define a subscription key on each of the environmen. In the below example i am creating a subscrption named dev on dev environment and prod on prod environment. You can check this link to understand how to create a subscription key. Once you creaete subscription keys on all three environment. You can add the following policy to your inbound policies.

<choose>
        <when condition="@(context.Subscription.Name=="dev")">
            <rate-limit-by-key calls="10000" renewal-period="15" counter-key="@(context.Subscription.Id)" />
        </when>
        <when condition="@(context.Subscription.Name=="prod")">
            <rate-limit-by-key calls="10000" renewal-period="15" counter-key="@(context.Subscription.Id)" />
        </when>
        <otherwise />
    </choose>

Once you done this next step is you need to make sure this subscription keys are being sent by the client. You can enable this on the settings.

If you don't want to create subscriptions and maintaining it. There is another way. Here the condition can be based on the name of the resource.

2. Second approach is pretty easy it is by referring any variables from context

Here you can refer a variable to distingush between your environment. like the below.

<choose>
        <when condition="@(context.Request.OriginalUrl.Host=="www.devenvironment.com")">
            <rate-limit-by-key calls="10000" renewal-period="15" counter-key="@(context.Subscription.Id)" />
        </when>
        <when condition="@(context.Request.OriginalUrl.Host=="www.prodenvironment.com")">
            <rate-limit-by-key calls="10000" renewal-period="15" counter-key="@(context.Subscription.Id)" />
        </when>
        <otherwise />
    </choose>

I think the second one is easy if you don't have any other constraints than the environments. You can actually refer any properties which is available on the context not only context.Request.OriginalUrl.Host

EDIT : About why example from this post is not excecuting as you expect is: context.Subscription.Name is not the subscription of your azure. It is the subscription you create under API manager, with which a client can access the APIs. I hope my answer describes with appropriate links

Justin Mathew
  • 950
  • 8
  • 34