set backend url after extracting it from header azure apim - azure

Hi I am trying to implement such a functionality where i need to make sure that the api is going through gateway so have created a apim and i need to extract header from the call and route to that call :
so far i have done this policy:
<policies>
<inbound>
<set-variable name="host" value="#(context.Request.Headers.GetValueOrDefault("uri","http://google.com/"))" />
<set-backend-service base-url="${{ variables.host}}" />
<base />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
but its giving error :
Error in element 'set-backend-service' on line 16, column 4: Value is not a valid absolute URL.

Error in element 'set-backend-service' on line 16, column 4: Value is not a valid absolute URL.
This probably means that the value of your uri header does not include https://. A valid absolute URL contains all the information necessary to locate a resource, including the protocol (HTTPS).
You can also set the value directly in the set-backend-service without using the set-variable first. Like:
<set-backend-service base-url="#(context.Request.Headers.GetValueOrDefault("header-name","optional-default-value"))" />

<set-backend-service base-url="#((string)context.Variables["host"])" />

Related

Set-AzApiManagementPolicy - How to set policy on multiple Operations

I am trying to understand how to apply custom policies (ie. Caching) to target each operations within an given API. Below is a sample cache policy file (xml) for a "Get Test1" policy:
<policies>
<inbound>
<base />
<cache-lookup vary-by-developer="false" vary-by-developer-groups="false" allow-private-response-caching="false" must-revalidate="false" downstream-caching-type="none" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
<cache-store duration="3600" />
</outbound>
<on-error>
<base />
</on-error>
So based on the above, I have several other operations within the same API that I want to apply unique policy to (Get Test2, Get Test3...). My understanding is that I need to execute a new Set-AzApiManagementPolicy for each operation I want to apply a policy to. Is this correct? This seem a bit tedious.
Can Set-AzApiManagementPolicy take a single XML file with various scopes defined within it?
Thanks

Trouble with Azure API Management TRACE policy rule not expanding variables in the message

Following the instructions from this page https://learn.microsoft.com/en-us/azure/api-management/api-management-policy-expressions and this page https://learn.microsoft.com/en-us/azure/api-management/api-management-advanced-policies#Trace , I am trying to define a TRACE policy rule in my inbound APIM API policy.
My rule looks like this but when it shows up in Application Insights, the variable hasn't expanded, not even if I use the simplest rule #(true) . https://learn.microsoft.com/en-us/azure/api-management/api-management-policy-expressions
Here is my policy:
<policies>
<inbound>
<base />
<trace source="me-apim.azure-api.net" severity="information">
<message>Requesting User: #(context.User)</message>
</trace>
</inbound>
<backend>
<forward-request />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Any idea what I might be doing wrong that causes the variable to not expand?
UPDATE: I found I was able to get this one to work. This suggests to me that maybe I am merely interacting with the context object incorrectly?
<trace source="me-apim.azure-api.net" severity="information">
<message>#( string.Join(":", "Current Time", DateTime.UtcNow) )</message>
</trace>
NOTE: Super helpful things I learned while working on this:
Using VS Code as an APIM debugger works like a charm.
The Azure ADO UX has a "snippets" thing that is really helpful when creating policy rules.
Yes, such variable expansion does not work at all, no matter the policy you try. The whole value should be either a constant or expression, not text with expression inside it. I.e., instead of:
<message>Requesting User: #(context.User)</message>
you could use as you found out:
<message>#( string.Join(":", "Current Time", DateTime.UtcNow) )</message>
Or a bit simpler using string interpolation:
<message>#($"Current Time:{DateTime.UtcNow})</message>
Or more specifically to original problem:
<trace source="me-apim.azure-api.net" severity="information">
<message>#("Requesting User: " + context.User.Id)</message>
</trace>
or:
<trace source="me-apim.azure-api.net" severity="information">
<message>#($"Requesting User: {context.User.Id}")</message>
</trace>

Policy to Avoid duplicate https calls on an Azure Api endpoint

I have some troubles regarding some duplicate calls on my Azure Api Endpoint. For example, I see that my endpoint :
tennis/getballs
has been called twice
First : 2020-11-02T18:07:19.8261667Z
Second :2020-11-02T18:07:19.881239Z
I want to avoid this second call which has the same payload (like "I don't do this call because it's too close than the first call", it's ok if it's 5 seconds later). I'm looking for something with the Policy but I didn't find something interesting.
Accourding to your description, maybe you want to add rate limit to your api. I think this document will help you.
This part describes how to prevent your api being called within short time. You can modify the policy to meet your custom request.
Enter api management webpage then select your target API > All operations > Design.
In the Inbound processing section, select the code editor (</>) icon.
Position the cursor inside the element and select Show snippets at the top right corner.
In the right window, under Access restriction policies, select + Limit call rate per key.
Modify your rate-limit-by-key code (in the element) to the following code:
calls="3" renewal-period="15" means you can call this api no more than 3 times within 15 seconds.
enter image description here
<policies>
<inbound>
<rate-limit-by-key calls="3" renewal-period="15" counter-key="#(context.Subscription.Id)" />
<base />
</inbound>
<backend>
<base />
</backend>
<outbound>
<set-header name="X-Powered-By" exists-action="delete" />
<set-header name="X-AspNet-Version" exists-action="delete" />
<redirect-content-urls />
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
After editing, you can call your api then you will find 429 Too many requests when calling too many times as your configuration.

Is there a way of varying the value of the rate limit by subscription in Azure API Management

In Azure API Management it's possible to limit call rates by subscription and key:
https://learn.microsoft.com/en-us/azure/api-management/api-management-access-restriction-policies#LimitCallRateByKey
My question - is there a way of varying the limit on calls and renewal period by subscription? So for example, subscription A can call an operation 100 times per minute but subscription B can call it 500 times per 10 seconds?
I think being able to have variables on subscriptions could solve this but I don't think that is possible. Is there any other way?
Thanks,
Chris.
If I get you right, this might be one solution:
<policies>
<inbound>
<base />
<choose>
<when condition="#(context.Subscription.Id == "123")">
<rate-limit-by-key calls="500" renewal-period="60" counter-key="#(context.Subscription.Id)" />
</when>
<when condition="#(context.Subscription.Name == "example-b")">
<rate-limit-by-key calls="100" renewal-period="60" counter-key="#(context.Subscription.Id)" />
</when>
<otherwise>
<rate-limit-by-key calls="10" renewal-period="60" counter-key="#(context.Subscription.Id)" />
</otherwise>
</choose>
</inbound>
<backend>
<base />
</backend>...
This way, I think you can vary the rate limit by specific subscription id's or names.

Reusing APIM policy expression via Named Value

I have a problem reusing APIM expression.
Specificially, a named value below is created like above,
name
JWTValidator
#(
#"<validate-jwt header-name='Authorization' failed-validation-httpcode='401' failed-validation-error-message='Error: expired token or invalid token' require-expiration-time='true' require-scheme='Bearer' require-signed-tokens='true'>
<openid-config url='xxx' />
<audiences>
<audience>xxx</audience>
</audiences>
<issuers>
<issuer>https://xxx</issuer>
</issuers>
</validate-jwt>"
)
and the policy below:
<policies>
<inbound>
<base />
{{JWTValidator}}
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
However, the policy element is removed and not inserted.
Any idea?
Is there a better way to reusing policy?
Upate
I want to define JWTValidator as Named value, and use it on Product level if possible, otherwise, API level.
Upate 2
I have changed to below, however, {{JWTValidator}} is auto-removed when it is saved.
Please note that the value of JWTValidator is saved successfully, which might mean the syntax is correct.
<policies>
<inbound>
{{JWTValidator}}
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-properties
https://learn.microsoft.com/en-us/azure/api-management/api-management-policy-expressions
Reusing APIM policy expressions
https://feedback.azure.com/forums/248703-api-management/suggestions/16951852-code-re-use-in-api-policies-using-of-custom-functi
This is actually UI issue. You should be able to see in browser dev tools that PUT request to save policy succeeds and returns proper saved content. It is UI merely removing property reference before presenting policy. Will be fixed soon.
Property may be used to fill in value of XML attribute or XML element in full. In your case you're trying to set value of in part with static element and in another part with property value. That is not supported, unfortunately. In other words, this is supported:
<inbound>
{{JWTValidator}}
</inbound>
and this is not:
<inbound>
<base />
{{JWTValidator}}
</inbound>
Property can only replace element value as a whole, and it cannot be used side by side with another element, like in your example, next to <base/>.
In you case I feel that it would be best to place this policy at outer scope: at API level if you need it applied to many operations, at Product/Global level if it's for multiple APIs. And have policy to apply it conditionally based on context.Operation.Id/context.Api.Id.

Resources