I am new to Azure API management. We are calling an external web api from Azure API management. If the web api is not able to communicate with the Azure API management, we are trying for a couple of retry before give up.
We have added a retry policy in the outbound node (policy) to check the response status of the backend node (policy). If the response status is other than 200 then we are trying to call the web api again after 10 seconds. We want to give 2 try before give up.
The problem is outbound node (policy) always execute send-request node (policy), even we just write
<retry condition="#(false)" count="2" interval="10" first-fast-
retry="false">
<send-request.....>
......
......
</send-request>
</retry>
How to write a condition in the retry policy so that it will get checked before executing the child nodes.
<outbound>
<base />
<retry condition="#(context.Response.StatusCode != 200)" count="2" interval="10" first-fast-retry="false">
<send-request mode="new" response-variable-name="responseVar" ignore-error="false">
<set-url>... </set-url>
<set-method>POST</set-method>
<set-body>...</set-body>
<set-header>...</set-header>
</retry>
</outbound>
Retry always executes its inner policies and only checks condition after first and subsequent executions. The idea is to check some result of inner policies to determine if they need to be executed again. To check condition upfront you'll have to wrap it into choose policy.
Related
I signed up for an API that retrieves a zip file and downloads it. For this, I received a bearer token.
I have created an apim instance and was looking to test the API I had subscribed to which downloads the file.
When I tested it, the apim instance kept loading and got stuck.
I tested this on Postman and it works perfectly. I got the "200 OK response", but still got weird characters like "�vt�" in my body, but that's probably because I'm retrieving a zip file. But why doesn't it work also within Azure's apim? Are there any extra policies I need to add?
Kind regards
You got the "200 OK response", but still facing the issue, you can try to troubleshoot by following approach:
1. If Backend section is taking most of the time (approx. 5 seconds), which means there is some slowness or long running operation is taking place at the backend.
Once you have isolated that the slowness is at the backend, you need to investigate the backend application code of the Web API application. For scenarios where you don't have access to the backend, you can implement caching at APIM level like below. Read about how you can implement caching policies to improve performance in Azure API Management.
<?xml version="1.0" encoding="UTF-8"?>
<policies>
<inbound>
<base />
<cache-lookup vary-by-developer="true" vary-by-developer-groups="true" must-revalidate="true" downstream-caching-type="public" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
<cache-store duration="60" />
</outbound>
<on-error>
<base />
</on-error>
</policies>
You can refer to REST API service when called from azure APIM returning empty response body with Status code 200,
Azure API Management returning 200 status without response body, gzip Compression, and Azure API management gives 200 response code,
I was wondering if there is the possibility to activate mocking for calls to an Azure API Management based API from the API Portal.
I don't want developers who browse the interface catalog and use the "try it" functionality to actually CRUD records from/in the backends. They should only receive a set of predefined data so they can develop against it without messing up the data in the backends.
Example
API is created on Azure API Management and productive.
This API is listed in the corresponding Azure API Portal -
a developer now finds that API and wants to try it out:
POST /SalesQuote would create a Sales Quotation in SAP. A developer uses the "try it" button in the developer portal to see the behaviour. The "send" button now actually creates a record in the backend.
Can this be prevented? If so - how? Would this be something that could be achieved within the API policy (i.e. mock data for origin = api portal url)?
The only other option I can think of would be disabling the try it feature - rather a bad solution.
EDIT: general "mocking-enabled" is of course for a productive API no option.
Thanks for your help!
Thanks to Nacho I researched the policy features more deeply and played around a bit. I came up with the following:
<inbound>
<base />
<choose>
<when condition="#(context.User.Groups.Any(Group => Group.Name == "developer-internal"))">
<mock-response status-code="201" content-type="application/json" />
</when>
</choose>
</inbound>
This should enable mocking only if the calling user is member of the group "developer-internal" (which are all developer portal users via AAD mapping).
As an alternative I am validating the re-routing option to our test backend instead of mocking the response which would look like this:
<inbound>
<base />
<choose>
<when condition="#(context.User.Groups.Any(Group => Group.Name == "developer-internal"))">
<!--mock-response status-code="201" content-type="application/json" /-->
<set-backend-service base-url="https://esb-test.example.com/restv2/CostObject" />
</when>
</choose>
</inbound>
Yes you can, you have to add a policy in the outbound of the API, normally I use it to expose apis that are in development process.
Go to the "Enable response mocking" part of this link:
https://learn.microsoft.com/en-us/azure/api-management/mock-api-responses
In azure API Management how to setup the 405 (Method not allowed) policy. I am using azure API management APIs and adding different policies like jwt validation, IP filtering, rate limit and all. But I couldn't find a way for add the 405 method not allowed in APIM. I want to setup this for each of the methods. That means I want to block the incoming unrecognized method requests from APIM. (eg: Get instead of POST (Throws 405 method not allowed from APIM). Currently APIM passes the wrong method to backend and it returns the 404 from the application. Anyone know how we can block the wrong request from APIM side and returns 405 instead of passing it to backend and returns 404?.
You could use a Control Flow policy along with the Context Variable on the Inbound policy of each Method to intercept any requests that don't match the defined http method and then use a Set Status policy to return a 405. So for a GET method something along the lines of:
<policies>
<inbound>
<choose>
<when condition="#(context.Request.Method.ToString() != "GET")">
<return-response>
<set-status code="405" reason="No Content" />
</return-response>
</when>
</choose>
<base />
</inbound>
... rest of policies
</policies>
If you've got multiple methods with the same path you might need to apply this at the API level rather than the Method level and make the condition equals methods not in use rather than not equal to method in use
To set this at the API level and check against a collection of methods not in use create a policy along the lines of:
<policies>
<inbound>
<choose>
<when condition="#{
ICollection<string> disallowedMethods = new List<string>() { "POST", "PUT" };
return disallowedMethods.Contains(context.Request.Method.ToString());
}">
<return-response>
<set-status code="405" reason="No Content" />
</return-response>
</when>
</choose>
<base />
</inbound>
... rest of policies
</policies>
The http methods not in use in this example are POST and PUT but you can change the list to whatever applies in your use case.
In my Azure API Managemenent I'm defining a header based caching policy at API level.
The policy is quite simple:
<policies>
<inbound>
<check-header name="token" failed-check-httpcode="400" failed-check-error-message="Token header is missing" ignore-case="true" />
<cache-lookup vary-by-developer="false" vary-by-developer-groups="false" downstream-caching-type="none">
<vary-by-header>token</vary-by-header>
</cache-lookup>
<base />
</inbound>
<backend>
<forward-request />
</backend>
<outbound>
<cache-store duration="3600" />
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
This works ok in the case my downstream returns a 200 with a body - next request with same header token will hit the cache and the response will be returned from the API Management cache.
However is a error code is returned by the downstream (eg: 401 Unauthorized) that response is not cached by the API Management (confirmed by the tracing I've enabled on the API Management).
I was under the impression that whole responses are cached, but this doesn't seem to be the case...
Can somebody let me know if it's possible to cache responses also in case of unsuccessful http codes and if yes point me to some doc - I've been googling all day yesterday, but was unable to find more.
Thanks in advance!
This is by design. If you look into traces you should see message there "Backend service responed with the status code of 401 rather than 200 OK. Cache Store policy was not applied." The reasoning is that at APIM level we assume that non 200 responses are more transient than 200.
Say that client gets 401, goes on to do whatever to make sure that token is allowed to do the operation and retries the call. And still gets 401 from cache until cache expires.
That certainly may be added as an extra configuration option on a policy: http://aka.ms/apimwish
You could workaround that by using cache-lookup-value and cache-store-value. I.e. in the outbound section if you get 401 store some value in cache using cache-store-value to keyed with token. And in the inbound before cache-lookup do cache-lookup-value with token and see if you get value stored earlier. If you do you can generate 401 response right in place.
How can you use policy to load balance calls to a pair of backend services? (in this case a pair of Logic Apps in different regions)
I've read through the API Management policies and can see something around the control flow but I can't work out how to (a) test the back-end service is available, and then (b) change the call to the backup service if the primary is unavailable
<backend>
<forward-request/>
</backend>
One more way to achieve this could be that you can use the retry policy with set backend service or send-request
with something like
<backend>
<retry condition="#(context.Response.StatusCode == 400 || context.Response.StatusCode >= 500)" count="10" interval="10" max-interval="100" delta="10" first-fast-retry="false">
<choose>
<when condition="#(context.Response != null && (context.Response.StatusCode == 400 || context.Response.StatusCode >= 500)">
<set-backend-service base-url="http://echoapibackup.cloudapp.net/api" />
</when>
<otherwise>
<set-backend-service base-url="http://echoapi.cloudapp.net/api" />
</otherwise>
</choose>
<forward-request />
</retry>
</backend>
This will in case your primary backend returns an error, will keep retrying on your backup backend.
Look into using send-request policy. With it (and wait policy) you could make parallel calls to a couple of web services and return result from one that completes first. That would mean that you need to skip forward-request altogether as you'll be getting result data from these policies.
Or you could use send-request to test if certain backend is available and then use set-backend-service and/or rewrite-uri policies to change destination backend. In that case you'll be keeping forward-request.