So we have a requirement where we need to access the Redis Cache directly from the APIM.The Redis Cache will be populated via some background jobs. Depending on the response from the Redis (the response will have a redirect uri) we need to redirect.
cacheclient = {
"userid" : "abcd"
"url1" : "url1",
"url2" : "url2",
"usertype":"normal"
}
My problem is whatever I try it is not reading from the Redis.
We don't need cache-store-value since data will always be in redis
I created an inbound policy
<when condition="#(context.Variables.ContainsKey("cacheduser"))">
hit
#((string)context.Variables["cacheduser"])
you can use an add an external redis , to add an external redis in apim, you have to go under the enter cache tab and click add
you have to fill the subsequent form and click save
After that you will have add policy in inbound tab and outbound tab in the inbound processing tab
under inbound tag
<cache-lookup vary-by-developer="false" vary-by-developer-groups="false">
<vary-by-header>Accept</vary-by-header>
<vary-by-header>Accept-Charset</vary-by-header>
<vary-by-header>Authorization</vary-by-header>
</cache-lookup>
under outbound tag
<cache-store duration="20" />
Refer this MS DOS on custom policy on caching
Related
I am having difficulty adding text into my url path between my frontend and backend when using Azure Api Management.
I have a Azure functions api with a url like this:
e.g. https://pXXXXX-myapi.azurewebsites.net/api/pXXXXX/alm/{name}
The default api created by Azure API Management is this:
e.g. https://myapi.azure-api.net/pXXXXX/pXXXXX/alm/{name}
Ideally I'd like to Frontend to remove the redundant pXXXXX:
e.g. https://myapi.azure-api.net/pXXXXX/alm/{name}
If I remove it from the front end e.g. GET /pXXXXX/alm/{name} becomes GET /alm/{name}.
Then I receive a 500 error.
I assume this is because removing "/pXXXXX" removes it from the backend path as well.
So I have tried to use the rewrite-uri policy like so:
<rewrite-uri template="/pXXXXX/alm/{name}" copy-unmatched-params="false" />
I've tried multiple variations of this with no success.
Assuming
you've changed the frontend for your operation to "GET /alm/{name}"
and your backend function app service url is "https://pXXXXX-myapi.azurewebsites.net/api"
and your API Base URL is "https://myapi.azure-api.net/pXXXXX"
then rewrite-uri exactly like you pasted is correct. You want to add leading "pXXXXX" to the url.
I've reproduced exact same scenario on my side and it works.
500 error does not mean there is something wrong with the path. If you would wrongly configure your url you would get 404. Most probably there is an internal error inside your function app or other policies in the APIM. Just call this API with Ocp-Apim-Trace header set to true and subscription key that allows tracing and you will see what is wrong. Or you can paste trace here if you want so we can help.
Posting my own answer but thanks to those who tried to help.
I believe the issue came from an error from APIM itself.
I assume it was not setting up the policies correctly, because now it is automatically including set-backend-service in the inbound policy whereas it did not over the past 2 days when I have been repeatably re-creating my api.
Now my inbound policy looks like this:
<inbound>
<base />
<set-backend-service id="apim-generated-policy" backend-id="pXXXXX-myapi" />
<rewrite-uri template="/pXXXXX/alm/{name}" copy-unmatched-params="false" />
</inbound>
And my front end api looks as before:
/pXXXXX/alm/{name}
I have an Azure App Service hosting an OData endpoint that is behind an Azure API Management (APIM) instance. To prevent calling the App Service directly it is protected by a certificate that only the APIM has.
When I call the APIM URL through Chrome or Postman, it behaves as expected. Just one request with no redirects or funny business, and it returns the OData root.
Here is a Fiddler log of a request to the APIM using Postman
However, when using the same URL as an OData source in Power Query using OData.Feed(), it returns a 301 which forwards to the backend URL, which obviously fails because that URL is protected by a certificate. Here is a Fiddler log of a request to the APIM using Power Query in Excel
I've configured the subscription key to be passed in the headers, but I've also tried it as a query param and it doesn't work in Power Query either way. I've also tried using an OData entity endpoint directly (to avoid the $metadata call) with no luck.
The user agent Power Query uses is Microsoft.Data.Mashup, but I haven't found any documentation about its compatibility with APIM, but that shouldn't matter, right?
In typical fashion after working on this for two days, I discovered the answer right after posting on StackOverflow. I'll leave this question up in case anyone has the same issue.
The problem was that the Power Query connector automatically follows #odata.context links for metadata, and #odata.nextLink links for paging. These links still had the app service site as the host instead of the APIM host.
So a quick edit of the outbound rules in APIM was able to fix the issue
<outbound>
<base />
<set-variable name="backendBaseUrl" value="#(context.Request.OriginalUrl.Scheme + "://" + context.Request.OriginalUrl.Host.ToString() + context.Api.Path)" />
<find-and-replace from="#("http://" + context.Request.Url.Host.ToString())" to="#((string)context.Variables["backendBaseUrl"])" />
<find-and-replace from="#("https://" + context.Request.Url.Host.ToString())" to="#((string)context.Variables["backendBaseUrl"])" />
</outbound>
Here I have to rules to replace http and https URLs just in case some configuration changes.
I am using Azure API Management as front end for my Logic App. The "subscription required" setting needs to be enabled as we do need the protection. However, we must send the key via query parameter because our calling application only supports GET, not POST.
So my API call was sent to Azure using the format of https://my.azure-api.net/myapi/manual/paths/invoke?subscription-key=mykey
Now in Azure API setting I did create a policy set to delete action on the "subscription-key" query parameter, but here's the problem:
Even though the parameter is removed from the request body into Logic App, upon digging into the "RAW" outputs in Logic App where it shows various headers, we can see the subscription-key in these two headers:
"X-WAWS-Unencoded-URL": "/myapi/manual/paths/invoke?subscription-key=xxx
"X-Original-URL": /myapi/manual/paths/invoke?subscription-key=xxx
In other words, the full original query URL was made available to Logic App before the parameter was removed. This exposes the API subscription key to the Logic App.
Is there any workaround for this?
Ah I see now that those headers were actually sent automatically by Azure API Management to the backend Logic App API, so all I had to do was to set header policies to remove them in addition to the query parameter policy.
<set-query-parameter name="subscription-key" exists-action="delete" />
<set-header name="X-WAWS-Unencoded-URL" exists-action="delete" />
<set-header name="X-Original-URL" exists-action="delete" />
This takes care of it.
Can we have API management end point exposed with out the subscription key sent as a part of headers?
It is possible to achieve this, you can do so via the product the API is associated with.
In the Publisher Portal go to the products menu and select the product the API is associated with (or even set up a new product just for the usage without the subscription key). Then select the settings tab and uncheck the Require Subscription checkbox and then save the settings.
Updated following comment by #sdementen
Please be aware in doing so, you will loose all metrics associated with the different users and any other functions that you may wish to apply differently to different consumers.
There is a very simple way to do this via the API Management interface.
On the APIs page, select your API, then click on the "Settings" tab. Scroll down to the "Subscription" section and uncheck the "Subscription required" option.
You will now be able to call your api without providing the subscription key either in the headers or as part of the querystring.
Another option is to send the subscription key in the URL, if you go to the developer portal and download the Swagger document of your API, you will see this:
{
"name": "subscription-key",
"in": "query",
"description": "subscription key in url",
"type": "string"
},
{
"name": "Ocp-Apim-Subscription-Key",
"in": "header",
"description": "subscription key in header",
"type": "string"
}
API management also accepts a subscription key in the querystring.
I tried creating a new product that does not require a subscription. I updated one of my APIs such that it was only associated with this new product. When I tested it, I got an 400 level error (I think a 401) that complained about the request not having a subscription id.
I contacted Azure support about this, and found out that it is a known bug. Copy/pasting the response here:
While investigating your issue, it seems that your APIM service has
encountered a known bug. Due to this bug, turning a product from
closed (requiring a subscription) to open (does not require a
subscription) does not always properly take effect. However, this can
easily be fixed by rebooting the VM the APIM service is hosted on. You
can do this by going to the VNET blade on the left side navigation
menu under the APIM and pressing the "Apply network configuration"
button at the top. This reboots the Dev SKU VM and should put you in
the proper position to not need subscription keys.
Upon rebooting, the APIM should be down for about 5 minutes, with 15
minutes being the maximum it should take to reset the VNET. When the
APIM comes back up, it may need an additional, small amount of time to
settle itself(maybe 5-10 minutes) then it should be good to go as
desired.
Microsoft has added a new scope for ocip-subscription-key in azure APIM which bypass the product scope. We can use this key in test console.
https://learn.microsoft.com/en-us/azure/api-management/api-management-subscriptions
Now problem is there is no way I can remove this key. If I send request from postman with this key in header my API bypass the Authorization header which is set at product level and calls my API.
I have restricted this header in my API with below code
<check-header name="Authorization" failed-check-httpcode="401" failed-check-error-message="Not authorized" ignore-case="false" />
<choose>
<when condition="#{
string[] value;
if (context.Request.Headers.TryGetValue("Ocp-Apim-Subscription-Key", out value))
{
if(value != null && value.Length > 0)
{
return true;
}
}
return false;
}">
<return-response response-variable-name="response">
<set-status code="401" reason="Unauthorized" />
<set-body>
{"statusCode": 401,"message": "Subscription key not allowed"}
</set-body>
</return-response>
</when>
</choose>
Here 1st I am checking that request should contain Authorization header. And after that I am sending error if request contains ocip-subscription-key.
Is there any better way I can stop my request sending global ocip-subscription-key
Thanks
I want to record the timings for the backend web service being fronted by the API Management service. We front a few 3rd party services so the only way we can get performance data is to log the backend request before and after. My plan was to utilise the base policy (All APIs / All Operations) like this
<backend>
<!-- log start of request -->
<forward-request />
<!-- log end of request -->
</backend>
But trying this I get;
Error in element 'backend' on line XX, column XX: backend section
allows only one policy to be specified
Can you have any policy expressions in the backend element?
backend section is very limited in what policies are allowed there. Your best option would be to do your logging last thing in inbound and first thing in outbound. You can control what policy is executed first by moving "base" tag to a desired position, it effectively controls when (and if) upper level policies are executed.
You can use Log to EventHub in this case to log whatever you want for a given request (which has Id you can use as correlation id).