How to send Query Parameter to Logic App from API Management - azure

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

Related

Azure API Management - dynamic urls issue

I have a frontend url say - 'https:\test.helloweb.com\account' which is defined a post request /person and I want to direct any request that comes on that url to a backend url like so
'https:\secure.hiddenapi\vi\api\person'.
The above scenario is easy and works now the place where I'm stuck is if there is a request for
Say -
/person/<id>/membership
/person/<id>/membership/<memid>
/person/<id>/accountdetails/
these requests needs to be directed to
https:\\secure.hiddenapi\vi\api\person\<id>\membership
https:\\secure.hiddenapi\vi\api\person\<id>\membership\<memid>
https:\\secure.hiddenapi\vi\api\person\<id>\accountdetails.
I tried defining the operation as /person/* then if i make a request to /person/<id>/membership then the backend url called is https:\\secure.hiddenapi\vi\api\person\membership without the id.
Seems like a simple issue but cannot make any progress!
Here is how APIM maps URLs. Consider:
An API with:
API URL suffix set to "myapi"
Web service URL set to "https://contoso.com/api"
An operation with:
URL template: "/myoperation"
When APIM receives a request it will split it into two parts:
https://service.azure-api.net/myapi/myoperation
^ ^
API base URL operation path
It will then replace API base URL with "Web service URL" specified for matched API and this will become request to backend:
https://contoso.com/api/myoperation
In your case, given that you end up with "person/person" it is likely you have "person" in both Web service URL and operation URL template. So you have two options.
First option is to configure Web service URL as "https://secure.hiddenapi/vi/api" and let all your operation templates start with "/person".
Another way is to set service URL as "https://secure.hiddenapi/vi/api/person" and do not include "/person" into your operation URL templates. It's perfectly fine if operation URL template starts with a variable like "{id}/membership/{memid}".
It's a good practice to split your whole backend API into different APIs in APIM for control and management. So personally I'd prefer first option, and if later there would be a need to make request to backend with prefix different than "/person" I'd create another API.
Try using rewrite URL policy to route to different backend URL for specific operation as follows:
<inbound>
<base />
<rewrite-uri template="/accountdetails/" />
</inbound>

Azure API Management "rewrite-uri"

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}

Why does Power Query call Azure API Management backend URL?

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.

How to prevent Azure API Management from passing the subscription-key query parameter to Logic App?

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.

Poll a Durable Function inside an Azure API Management request

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.

Resources