Is it possible to do a short polling internally in an APIM request then respond with sync response?
The flow goes like this:
1. APIM receives a request
2. APIM triggers a durable function orchestration.
3. APIM waits and polls the durable function response (through a policy?)
4. APIM responds with the actual result
To the API Consumer, it will be a single request.
Is this a common pattern? Or is it better to just provide the 202 Response polling URL to the API consumer? I'm expecting the request to take only around a few seconds to under a minute.
Is there a more standard way of doing this that I haven't considered yet?
It is subjective to how you want your API to be presented to the consumers.
If you want the front end users to poll the API then 202 Accepted response with a polling url in location header is the way.
If you want to disguise your API as a synchronous API , you will have to implement the polling pattern itself inside the APIM policy. For this refer following post
Use API-M To Mask Async APIs When Moving Implementation to Logic Apps, even though it pertains to logic app, you can implement the same pattern for any async API
excerpt from the link:
<outbound>
<base />
<retry condition="#(((IResponse)context.Variables["var"]).StatusCode == 202)" count="10" interval="30">
<send-request mode="new" response-variable-name="var" ignore-error="false">
<set-url>#(context.Response.Headers["location"][0])</set-url>
<set-method>GET</set-method>
</send-request>
</retry>
<return-response response-variable-name="var" />
</outbound>
As I pointed out earlier, it really depends upon how you want your API to be presented to your consumers. Both patterns are valid.
Related
I have API 1 which is defined by int-http:inbound-gateway and has service activator to perform some business logic and sends output on output channel same as reply channel of the inbound gateway(simple flow)
I also have API 2 which is defined in different xml file which also has int-http:inbound-gateway and int-http:outbound-gateway which performs on its own.
Now I want to call API 2 from API 1 but I don’t want to send message of the output channel of first API 1 to API 2, API 1 output channel response if for the end user to consume!
If I use request channel of the API 2 as output channel of API 1, I am thinking I will lose the output of the API 1.
Would you please help how this can be achieved?
Edit :
API 1(there is no need of outbound gateway as this API is doing db operations)
<int-http:inbound-gateway
request-channel="aRequestInputChannel"
reply-channel="aOutputChannel"
supported-methods="POST"
path="/perform"
mapped-request-headers="*"
request-payload-type="com.test.spring.integration.LPRequestPayload">
<int-http:request-mapping consumes="application/json" />
</int-http:inbound-gateway>
<int:service-activator input-channel="aRequestInputChannel" ref="IBAdapterController" method="attachData" output-channel="unRequestChannel"/>
API 2:
<int-http:inbound-gateway
request-channel="unRequestChannel"
reply-channel="unResponseChannel"
supported-methods="POST"
path="/test/unOp"
request-payload-type="com.test.spring.integration.LPRequestPayload"
mapped-request-headers="userId, userName, languageCode, HTTP_REQUEST_HEADERS" >
<int-http:request-mapping consumes="application/json,application/xml" />
<int-http:header name="userId" expression="#requestParams[userId]"/>
</int-http:inbound-gateway>
<int:service-activator input-channel="unRequestChannel" output-channel="unOutputChannel" ref="unAdapterController" method="getUnOpDetails" />
so here if I use output-channel="unRequestChannel" of first api as request channel of API 2,
I am loosing original payload as I am sending http response entity from the controller of the first api. I will need to send LPRequestPayload from first api which is not the requirement. as I am performing some db operation if first api, I need to send its response to the end user.
API 2 is like some mandatory operation that needs to be done after db operation is done.
You need to provide more info about your configuration and use-case.
It is not clear if you are going to call API instead of just replying from the service activator or in addition.
You may also learn that there is no need in the reply-channel in the inbound gateways and output-channel in the last in the flow endpoint. An inbound gateway always populates a replyChannel header and an endpoint (e.g. service activator) without an output-channel is going to produce its reply message exactly into that replyChannel from headers. So, it it might be possible that your requirements are met very easy:
inbound gateway 1 > request channel 1 -> service activator -> request channel 2
inbound gateway 2 > request channel 2 -> outbound gateway 2
With this configuration it doesn't matter if you have that inbound gateway 2 or not, the outbound gateway 2 is always going to reply to the replyChannel header from a request message. Therefore in your case when you initiate request from the inbound gateway 1, the outbound gateway 2 is going to reply back to that one. If you request via inbound gateway 2, then reply will come back exactly into this request initiator. The Reply Address pattern with its power.
We've an Azure based solution that tracks user actions on a SharePoint web site. A SharePoint extension produces a JSON payload that is sent to an API Management resource with the task to log it to Event Hub.
Useless I describe next parts of the architecture since will go beyond the purpose of the question.
We're used to deploy the whole solution automating DevOps with a custom software.
In the last deploy the APIM seems unable to work properly. The request took about 3 minutes and ends with 502 - Web server received an invalid response while acting as a gateway or proxy server.
I get this error using postman where it should normally return a mocked 200 after logging to Event Hub.
This is the XML policy used:
<set-body>#{
var body = context.Request.Body.As<JObject>();
body.Add(new JProperty("event_id", Guid.NewGuid().ToString()));
body.Add(new JProperty("ip_address", context.Request.IpAddress));
body.Add(new JProperty("ingest_status", "unknown"));
return body.ToString();
}</set-body>
<log-to-eventhub logger-id="pagesLogger">#(
context.Request.Body.As<string>(preserveContent: true)
)</log-to-eventhub>
<mock-response status-code="200" content-type="application/json" />
This is the top-level ALL APIs policy:
<cors>
<allowed-origins>
<origin>*</origin>
</allowed-origins>
<allowed-methods>
<method>GET</method>
<method>POST</method>
<method>OPTIONS</method>
</allowed-methods>
<allowed-headers>
<header>*</header>
</allowed-headers>
</cors>
The weird thing is that also commenting log-to-eventhub I get an error response: 500 - The request timed out.
I tried to create another API in the same APIM resource but I'm still unable to get a 200 from a mocked response. Also creating a brand new APIM resource it's not able to solve the problem.
Enabling application insights on APIM did not help to get further informations. The same also with Event Hub diagnostics.
I don't expect a solution but I would really appreciate hints that help me diagnose the problem.
It was an Azure issue. Without changing anything after two days everything
is back to normality
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.
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).
I am receiving a GET request in API management (https://devapi.testcustomer.com.au//bankv2?bsbNumber=123-456) and transforming it to POST call to Logic App. How can I pass the bsbNumber query parameter from the incoming request to Logic App?
I am setting the logic app Url inside API Policy:
<set-backend-service base-url="https://prod-05.*******.logic.azure.com:443/workflows/******b187aef1f5/triggers/request/run" />
<set-method>POST</set-method>
<rewrite-uri template="?api-version=2016-06-01&sp=%2Ftriggers%2Frequest%2Frun&sv=1.0&sig=*****tdiDL8" />
You will have to use the expression context.Request.Url.Query.GetValueOrDefault("bsbNumber")
to get the value of bsbNumber from querystring. You can use it to create a parameter in the redirect URI.
List of all possible expressions in Azure API managment.
https://msdn.microsoft.com/en-us/library/azure/dn910913.aspx