is it possible to send only error logs to event hub? - azure

I created a diagnostics setting in azure apim and send logs to event hub.
But now the requirement is I need to pass only the error logs from azure api management to event hub.Current setting passes all the success and failure logs into event hub.
is there any way to filter logs before sending it into event hub or log only errors.

To achieve this I would check response status code and only send to eventhub in case of an error in outbound section e.g. of the all operations policy:
<policies>
<inbound>
<base />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
<choose>
<when condition="#(context.Response.StatusCode.ToString() >= "400")">
<log-to-eventhub logger-id ="ehLogger">
#(...)
</log-to-eventhub>
</when>
<otherwise>
</otherwise>
</choose>
</outbound>
<on-error>
<base />
<log-to-eventhub logger-id ="ehLogger">
#(...)
</log-to-eventhub>
</on-error>
</policies>
This is for response errors from the backend. If you're referring to errors happening in request / policy processing, you would only send from on-error section. See here for more information.

Related

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}" />

Azure APIM Policy - When to use <backend> </backend>

https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-policies
<policies>
<inbound>
<!-- statements to be applied to the request go here -->
</inbound>
<backend>
<!-- statements to be applied before the request is forwarded to
the backend service go here -->
</backend>
<outbound>
<!-- statements to be applied to the response go here -->
</outbound>
<on-error>
<!-- statements to be applied if there is an error condition go here -->
</on-error>
</policies>
When do we use backend sections in the policy?
Looks like setting the backend url using is also done on <inbound> node only.
Thanks for your time.
that part is used to do any transforms\checks on the request before forwarding it to the backend, for example I was adding headers to the request and validating oauth tokens.

Azure APIM as pure proxy

I am trying to deal with an Backend API(REST) with no swagger documents to be accessed through Azure APIM.
I want all the calls directed to the Backend API with me not manually creating GET/PUT/POST for all the resources. My inbound policies for all operations is below
'
<policies>
<inbound>
<set-variable name="requestPath" value="#(context.Request.Url.Path)" />
<base/>
<set-backend-service base-url="https://*****/****/" />
<rewrite-uri template="#(context.Request.Url.Path)" copy-unmatched-params="true" />
</inbound>
<backend>
<base/>
</backend>
<outbound>
<base/>
</outbound>
</policies>
`
However when hit the APIM i was given
{
"statusCode": 404,
"message": "Resource not found"
}
Any help is appreciated Thanks
The easy way to do this is to create one operation for each HTTP method you support and use /* for the template. This will match any inbound path/query and forward it to the backend.

Resources