URL Based routing on Azure - azure

I am trying to do URL based routing for my APIs but I am not able to achieve as my API endpoints contain a wildcard in the middle of the URL, like:
/prodapi/v1.0/{appId}/level
/prodapi/v1.0/{appId}/products
appId is my customers white label ID, so it's unique for all our customers.
So far I have tried :
Azure application gateway [ But you can only handle at the end of your URL]
Azure Fron door [Have the same settings]
API management [ Not allowing me to do wildcard]
Can someone help me with any azure native or Out of the box solution.

If you want to route the traffic depending on a specific path parameter, you could use Api management service and write a inbound policy as such:
<policies>
<inbound>
<base />
<set-variable name="appId" value="#(context.Request.MatchedParameters["appId"])" />
<choose>
<when condition="#(int.Parse(context.Variables.GetValueOrDefault<string>("appId")) == 1)">
<set-backend-service base-url="https://google.com/" />
</when>
<when condition="#(int.Parse(context.Variables.GetValueOrDefault<string>("appId")) == 2)">
<set-backend-service base-url="https://twitter.com/" />
</when>
<otherwise>
<set-backend-service base-url="https://facebook.com/" />
</otherwise>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Replacing the backend-service with your prefer url ofc :)
API management is very powerful, so I'm sure that you'll find the solution there if this is not what you were looking for.

Related

How do I specify a policy so that Azure API Management creates a different response cache for each combination of query parameters?

How do I specify a policy so that Azure API Management creates a different response cache for each combination of query parameters?
Suppose I have an endpoint /my-endpoint that takes 2 query parameters (item_id and language).
I want API Management to make a different cache for each combination of my query parameter values.
For example, I want the following requests to store different cache values for the responses:
/my-endpoint?item_id=4&language=en
/my-endpoint?item_id=4&language=nl
/my-endpoint?item_id=2&language=en
/my-endpoint?item_itd=2&language=nl
How do I do this?
In particular, do both of the following APIM policies (APIM Policy 1 and APIM Policy 2) work? Or is there a difference in how Azure API Management response caching works when I use a single tag with values separated by commas (see APIM Policy 1), or when I use multiple tags, each with a different value (see APIM Policy 2)?
APIM Policy 1
<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">
<vary-by-query-parameter>item_id;language</vary-by-query-parameter>
</cache-lookup>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
<cache-store duration="3600" />
</outbound>
<on-error>
<base />
</on-error>
</policies>
APIM Policy 2
<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">
<vary-by-query-parameter>item_id</vary-by-query-parameter>
<vary-by-query-parameter>language</vary-by-query-parameter>
</cache-lookup>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
<cache-store duration="3600" />
</outbound>
<on-error>
<base />
</on-error>
</policies>
If you don't get the "vary-by-query-parameter" to work, you could do something like this:
<cache-store-value key="#("my-variable-" + context.Request.MatchedParameters.GetValueOrDefault("item_id","")) + "-" + context.Request.MatchedParameters.GetValueOrDefault("language",""))" value="#(context.Response.Body.As<String>(true))" duration="3600" />
In this way you combine your parameters to get unique cache variabel names.
Given your case above you will have 4 different cache variables:
my-variable-4-en
my-variable-4-nl
my-variable-2-en
my-variable-2-nl
They will all contain different response bodies.

Azure API Management - named value at API scope

I am wondering whether it is possible to specify something like Named value but for each API separately?
So if I have, say foo-API and bar-API I can specify for each a named value-like variable, eg my-url. So now when I create a global policy
<policies>
<inbound>
<base />
<send-request mode="new">
<set-url>{{my-url}}</set-url>
<set-method>POST</set-method>
<set-body>something</set-body>
</send-request>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
but send-request will send request to the API specific URL (eg. different URL for DEV, TEST, PROD)
Not possible. Named values are a global collection, the only workaround is to name them to be descriptive enough, i.e. prefix with API id.

Azure APIM - Policy - Cannot get valid context - Error 500 - Object Not Set to Instance of Object

Referring to this page: https://learn.microsoft.com/en-us/azure/api-management/policies/send-request-context-info-to-backend-service
I am trying to get the User.Group using a policy such that I can restrict access to CRUD operations based on membership of 'read-only' or 'full-access' group.
All of the Microsoft Docs state that you can get user context by accessing #(context.User) and then whatever property you want. My proposed policy was this:
<policies>
<inbound>
<rewrite-uri template="/views/foo" />
<base />
</inbound>
<backend>
<base />
</backend>
<outbound>
<choose>
<when condition="#(context.User.Groups.Select(g => g.Name).Contains("Read-Only-Group"))">
<return-response>
<set-status code="403" reason="Unauthorized" />
<set-body>You do not have write access - this operation is not available</set-body>
</return-response>
</when>
</choose>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
The problem I am having is that whichever basic examples I try and implement in policy, I am getting "Error 500 - Object not set to an instance of object" whenever I try and get anything to do with the User. I understand this means my User object is not populated, but I don't get why.
Even if I refer to the basic examples on the Microsoft page to set some headers containing the Product name and User ID, they fail with the same error. Those pages don't contain any info on additional steps needed to access the User object.
How can I access these items?
I used https://reqbin.com/echo/get/json as a mock backend and this API operation policy:
<policies>
<inbound>
<rewrite-uri template="/echo/get/json" />
<base />
</inbound>
<backend>
<base />
</backend>
<outbound>
<choose>
<when condition="#(context.User.Groups.Select(g => g.Name).Contains("Developers"))">
<return-response>
<set-status code="403" reason="Unauthorized" />
<set-body>You do not have write access - this operation is not available</set-body>
</return-response>
</when>
</choose>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
I set the API to subscription required.
When running an operation with a subscription key of a product valid for the API, I get the correct response (as everybody is in group Developers by default):
You do not have write access - this operation is not available
Then unchecking subscription required and running the operation without a subscription key gives me:
{
"statusCode": 500,
"message": "Internal server error",
"activityId": "46600c4a-960a-479e-a634-8e2857cea512"
}
Hence, when you want to access context.User object, you need to work with an API which has subscription required.

Is it possible to create a policy that will conditionally expose an api management endpoint in azure even when a opim-subscription key is required?

An example of what I am looking for is as follows but the allow-access element does not exist. What can I replace with so that the subscription key is not checked. i.e. in this case it would allow all callers access to the controller as long as they are making GET requests.
<policies>
<inbound>
<base />
<choose>
<when condition="#(context.Request.Method.Equals("GET"))">
<allow-access />
</when>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
Any help would be appreciated.
A workaround would be to turn off the Requires subscription setting on the product and check the subscription key in the inbound policy by yourself. Here is an example of how to do it.
Go to Settings of Starter product.
Uncheck Requires subscription and save.
Open the policies of the product and add the following policy to the inbound. The value of <check-header> policy is the subscription key of the Starter product.
<choose>
<when condition="#(!context.Request.Method.Equals("GET"))">
<check-header name="Ocp-Apim-Subscription-Key" failed-check-httpcode="401" failed-check-error-message="Not authorized" ignore-case="false">
<value>920b4e307f4f41ff9bd4a3bd6a5450ee</value>
</check-header>
</when>
</choose>

How to pass parameters in API request to back-end URL with Azure APIM?

I'm trying to create a request with parameters in Azure API Management.
I have the following API(returns all invoices):
www.apibackend.com/invoice
This API can also handle parameters like this(returns invoice with ID 1):
www.apibackend.com/invoice/1
In my APIM service I've got the following code:
<policies>
<inbound>
<base />
<set-backend-service base-url="www.apibackend.com/" />
<rewrite-uri template="/invoice" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
With the APIM URL(for example: www.apim.com/test/GetInvoices) I can make the following request to my backend:
www.apibackend.com/invoice
This will return all the invoices, but how do I only retrieve the invoice with ID 1? If i make the request "www.apim.com/test/GetInvoices/1" I will get an error.
Hope someone can help!
In APIM change your Operation template to GetInvoices/{id} then in policies you'll be able to do:
<rewrite-uri template="/invoice/{id}" />

Resources