Can Azure Api Management expose OpenAPI documentation? - azure

We have some Azure Functions exposed through Api Management? Can Api Management expose a /swagger endpoint automatically, the same way the Swashbuckle package does for api's in Asp.Net.

Azure API management cannot automatically generate the swagger page. Azure API management only can provide you the API definition file. Then you can use other tools (such as Swagger UI) with the definition file to generate the page you need.
Besides, Azure API management has provided you the UI(https://youapimanagementname.portal.azure-api.net) to tell you how to use all the APIs.

You can expose your openapi documentation through the API itself.
The documentation of an API can be requested on
https://management.azure.com/subscriptions/[subscriptionid]/resourceGroups/[resourcegroupname]/Microsoft.ApiManagement/service/[servicename]/apis/[apiid]?export=true&format=openapi&api-version=2021-01-01-preview
Just create an additional operation (ex. openapi.yaml) on your API, call the url above through a custom policy and return the result. You can use the following policy
<policies>
<inbound>
<base />
<send-request mode="new" response-variable-name="result" timeout="300" ignore-error="false">
<set-url>#("https://management.azure.com/subscriptions/{{azure-subscriptionid}}/resourceGroups/{{azure-resourcegroup}}/providers/Microsoft.ApiManagement/service/" + context.Deployment.ServiceName + "/apis/" + context.Api.Id + "?export=true&format=openapi&api-version=2021-01-01-preview")</set-url>
<set-method>GET</set-method>
<authentication-managed-identity resource="https://management.azure.com/" />
</send-request>
<return-response>
<set-status code="200" reason="OK" />
<set-header name="Content-Type" exists-action="override">
<value>application/yaml</value>
</set-header>
<set-body>#((string)(((IResponse)context.Variables["result"]).Body.As<JObject>()["value"]))</set-body>
</return-response>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
More info can be found on https://www.devprotocol.com/2021/07/20/expose-openapi-documentation-on-azure-api-management.html

Related

URL Based routing on 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.

Azure Blob List "Value for one of the query parameters specified in the request URI is invalid" when using API Management service

I'm using API Management service to make a simple interface between a c# desktop application and a Azure Blob storage account.
API Management service is providing the authentication via a Subscription Key. This works fine for downloading blobs.
I also want to list the contents of an individual container / folder (prefix) using the same method.
I've tested the following HTTP call outside the API Management service, it works correctly.
https://<account>.blob.core.windows.net/files?restype=directory&comp=list&prefix=globalpackages/1.0
When I use this in API Management service, I'm returned an error:
<Error>
<Code>InvalidQueryParameterValue</Code>
<Message>Value for one of the query parameters specified in the request URI is invalid.
RequestId:917b0aa8-101e-006b-0709-8e85b0000000
Time:2022-07-02T11:47:29.0834806Z</Message>
<QueryParameterName>comp</QueryParameterName>
<QueryParameterValue>list</QueryParameterValue>
<Reason />
</Error>
My processing rules:
<policies>
<inbound>
<base />
<set-header name="Ocp-Apim-Subscription-Key" exists-action="delete" />
<set-header name="Sec-Fetch-Site" exists-action="delete" />
<set-header name="Sec-Fetch-Mode" exists-action="delete" />
<set-header name="Sec-Fetch-Dest" exists-action="delete" />
<set-header name="Accept" exists-action="delete" />
<set-header name="Accept-Encoding" exists-action="delete" />
<set-header name="Referer" exists-action="delete" />
<set-header name="X-Forwarded-For" exists-action="delete" />
<set-header name="x-ms-version" exists-action="override">
<value>#{string version = "2017-11-09"; return version;}</value>
</set-header>
<set-backend-service base-url="#{
return String.Format("https://<storageaccount>.blob.core.windows.net/files?restype=directory&comp=list&prefix=globalpackages/1.0");
}" />
<authentication-managed-identity resource="https://storage.azure.com/" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
what am I doing wrong?
Based on the documentation available here, the query parameter should be restype=container instead of restype=directory if you need to list blobs inside a blob container.
Once you make this change, you should be able to list the blobs.

Azure API Management with multiple backends

I have an Azure API Management set and running. The API calls are made to a Docker container running FastAPI on an Azure virtual machine. This backend container is responsible for running some AI models based on the queries it receives. It all works fine for a single user.
The thing is: these AI models are defined in a config file inside the container and are user-specific.
I want to use Azure API Management to route requests based on, say, the user subscription. In other words, given a subscription, I want to know which backend to call (each backend would be a container running a specific AI model for that particular user/company on an Azure virtual machine).
What is the best way to approach this?
I found out that you can use inbound policies to specify which backend to use depending on what group the user belongs to. The reference to my answer comes from here.
Go to your API Management, choose Groups and create groups that are relevant to your users. Then add your users to their respective groups.
Go to your API, select inbound rules and specify your backends using something like this:
<policies>
<inbound>
<choose>
<when condition="#(context.User.Groups.Select(g => g.Name).Contains("org1"))">
<set-backend-service base-url="https://abc-apim.azure-api.net/org1app" />
</when>
<when condition="#(context.User.Groups.Select(g => g.Name).Contains("org2"))">
<set-backend-service base-url="https://abc-apim.azure-api.net/org2app" />
</when>
<otherwise>
<return-response>
<set-status code="401" reason="Unauthorized" />
<set-header name="WWW-Authenticate" exists-action="override">
<value>Bearer error="Invalid user group"</value>
</set-header>
</return-response>
</otherwise>
</choose>
<base />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
I undestand this approach is not so elegant, since you have to hard code the backend routing in your policy. But it works.

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

Is it possible to use the subscription-key query string parameter with Azure API Management SOAP-passthrough?

We use API Management to expose several API's. One of the API's we expose is configured as a SOAP-passthrough API but we are facing some issues with it regarding authentication of APIM.
When we use the Ocp-Apim-Subscription-Key header for passing the query string it all works correct and the API is returning it's content correct.
When we use the subscription-key query string parameter the API is returning a 401 Unauthorized. I tested this behavior in Postman and changing the way of sending the subscription key is resulting in this behavior.
An implementation detail of this API is that it exposes an existing WSDL and routes this SOAPAction to an Azure Function via the policy. In the Application Insights of the function I can verify that the function is never invoked when I get a 401 but it is invoked when I get a successful call (using the header).
Is this normal behavior? Am I doing things wrong? Or is it a bug in APIM?
This might be an issue with the way we do routing for SOAP Passthrough. You will notice in the API setup that we add on a query parameter to identify the SoapAction that an operation will be matched to. It may be that your the api key query parameter is getting overwritten when adding the SoapAction parameter to the inbound request. I will investigate and let your know.
We currently use a workaround around this problem with the following policy. Instead of changing the backend-server url in the policy we send a request and set the response of that request as a response for this api. Below you can find our policy which is working with the subscription-key in the query string.
<policies>
<inbound>
<base />
<send-request mode="copy" response-variable-name="response" timeout="20" ignore-error="false">
<set-url>{{BackendServer_URL}}</set-url>
</send-request>
<!--return-response response-variable-name="reponse" /-->
<choose>
<!-- If StatusCode is not OK, return Unauthorized with the reason. -->
<when condition="#(((IResponse)context.Variables["response"]).StatusCode != 200)">
<return-response response-variable-name="reponse">
<set-status code="401" reason="Unauthorized" />
<set-body>#(((IResponse)context.Variables["response"]).Body.As<string>())</set-body>
</return-response>
</when>
<otherwise>
<return-response response-variable-name="reponse">
<set-status code="200" />
<set-header name="Content-Type" exists-action="override">
<value>text/xml; charset=utf-8</value>
</set-header>
<set-body>#(((IResponse)context.Variables["response"]).Body.As<string>())</set-body>
</return-response>
</otherwise>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>

Resources