In today’s post, I want to talk about using Azure API Management (APIM) along Dynamics 365 Finance and Operations.
Azure API Management is a hybrid, multi-cloud management platform for APIs across all environments. This means that, after deploying an APIM account, you can create an API that can serve services from one system or multiple.
Why would I put Azure API Management in front of D365’s services/OData?
That’s a legitimate and excellent question. We already have OData and custom web services, and both can be easily accessed.
Well, of course OData and WS are perfectly fine, but by using Azure API Management we can add an extra layer of several things:
- Add extra security and decoupling your APIM API from the backend one. Forget about passing the Azure AD App ID and secret to an external provider, you can manage that inside APIM and give an API Key to whoever is consuming your API.
- Add limit call rates, or usage quotas.
- Validate the request or response body.
- Validate parameters.
- Custom policies and custom responses.
And of course, you can have several backends in a single API. This means you could have the CRM WebAPI and ERP OData endpoints in the same URL. And also deploy a self-hosted gateway to connect to support hybrid and multi-cloud environments.
And a lot more feature, I’ve just scratched on the surface of Azure API Management.
Use it with Dynamics 365 F&O
Create API Management account
Go to your Azure account and look for “API Management services” in the top search bar. Select create and fill in all the fields.
Regarding the pricing tier, I’d go with the “Consumption” one which gives us a million calls per subscription, and after that it’s like 3 cents/10K calls. Keep in mind that if you wish to have a developer portal with your API’s documentation, you’ll need to get any of the other tiers.
When creating the API Management, you can also enable Application Insights and select several protocols. All of these can be enabled or changed after creating the APIM.
Depending on the tier you’ve selected, the APIM will take from minutes to up to an hour to be deployed. If the tier includes a developer portal, it’ll take more time.
Create an API
Now it’s time to create a new API, so head to the API menu on the left. You have several choices:
You can import OpenAPI definitions, WSDL for SOAP services, etc. but we’ll choose the HTTP one. Give it a name and enter your Dynamics 365 environment URL, including the /data in this case because I’ll be showing it using OData.
If you were creating an API Management for custom web services you’d add the /api/services suffix.
The Designer
I won;t go much into detail but this is something it’s worth mentioning. The designer gives us a clue about how API Management work:
You can see a “Frontend” which is our APIM API URL and where the user will make a request.
Then an “Inbound processing” box where you can set some rules before that will be applied to the incoming request and passed to the “Backend” API.
And finally an “Outbound processing” box where the backend API sends the request and where we can change some things before returning them to the “Frontend” and display them to the customer that called the APIM API.
Create new operation
Now we need to create a new operation, so click on Add operation and fill in the fields:
Click save and let’s test it! Go to the Test tab, copy the request URL and paste it to a different tab and let magic happen!
Too quick! Go to the settings tab, and you’ll see a Subscription section:
And now you can do two things:
- Uncheck the subscription required box.
- Add a header parameter to the URL with the value of your subscription key, found on the “Subscriptions” menu on the left. That’d leave our URL as https://apimd365.azure-api.net/CustomerGroups?subscription-key=YOUR_SUBSCRIPTION_KEY.
But wait, there’s one more thing missing, and you must be asking how would I access an OData endpoint without getting the bearer token first. You’re totally right.
Get the token
Each time we call a Dynamics 365 F&O OData endpoint or web service, we need to authenticate with the bearer token. We’ll solve this thanks to the policies. GO back to the design tab and click the code symbol in the “Inbound processing” section while “All operations” is selected:
An XML editor will appear, and you need to add an Azure App ID and secret here to get the token and authenticate:
<!--
IMPORTANT:
- Policy elements can appear only within the <inbound>, <outbound>, <backend> section elements.
- To apply a policy to the incoming request (before it is forwarded to the backend service), place a corresponding policy element within the <inbound> section element.
- To apply a policy to the outgoing response (before it is sent back to the caller), place a corresponding policy element within the <outbound> section element.
- To add a policy, place the cursor at the desired insertion point and select a policy from the sidebar.
- To remove a policy, delete the corresponding policy statement from the policy document.
- Position the <base> element within a section element to inherit all policies from the corresponding section element in the enclosing scope.
- Remove the <base> element to prevent inheriting policies from the corresponding section element in the enclosing scope.
- Policies are applied in the order of their appearance, from the top down.
- Comments within policy elements are not supported and may disappear. Place your comments between policy elements or at a higher level scope.
-->
<policies>
<inbound>
<base />
<send-request mode="new" response-variable-name="bearerToken" timeout="20" ignore-error="true">
<set-url>https://login.microsoftonline.com/YOUR_TENANT/oauth2/token</set-url>
<set-method>POST</set-method>
<set-header name="Content-Type" exists-action="override">
<value>application/x-www-form-urlencoded</value>
</set-header>
<set-body>@{ return "client_id=YOUR_CLIENT_ID&resource=ENVIRONMENT_URL&client_secret=YOUR_SECRET&grant_type=client_credentials"; }</set-body>
</send-request>
<set-header name="Authorization" exists-action="override">
<value>@("Bearer " + (String)((IResponse)context.Variables["bearerToken"]).Body.As<JObject>()["access_token"])</value>
</set-header>
<retry condition="@(context.Response.StatusCode == 429)" count="3" interval="20" max-interval="60" delta="20" first-fast-retry="false" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
You can copy this and just change the YOUR_TENANT, YOUR_CLIENT_ID, ENVIRONMENT_URL and YOUR_SECRET values. And now we can go back to the browser, paste our APIM URL and subscription key if you’ve left it enabled and:
We’ve successfully retrieved the customer groups through our API Management endpoint!
More good things
As you all know, Dynamics 365 F&O has throttling enabled, and in case there’s an operation that fails due to it, we’ll get a 429 response. We can implement retry policies in our API Management and whoever is using our APIM API can forget about doing it.
Go back to the Design tab and click on any of the code editors for policies, then in the backend node add:
<retry
condition="@(context.Response.StatusCode == 429)"
count="10"
interval="10"
max-interval="100"
delta="10"
first-fast-retry="false">
</retry>
This will do up to 10 retries. Isn’t it cool?
Use cases
I wouldn’t put an API Management in front of each Dynamics 365 implementation, of course, but there might be some scenarios where there are several 3rd parties accessing data, and you want to keep some control over who is accessing what.
Being able to enable Application Insights can also give us more detail on the usage and errors than LCS too.
And there’s a ton of other policies that you can set at the inbound, backend or outbound level. As I said I’ve only tried this a bit, but it has a lot of potential uses for Dynamics, now it’s your turn to try it out!
10 Comments
Nice article. I played around today with APIM and got the scenario described here working no problem. Thanks a lot, the policies would have taken some time to figure out. And there is a lot to explore, products, named values, backends, versions and revisions, …
Also love the built in monitoring with application insights. This should be very useful in an upcoming project.
Thanks Florian! Yes the policies can be really complicated, there are some examples in the docs if you want to check them.
Excellent article. I am currently participating in an effort to document and segment new custom services in D365FO, which will be used by various Hubs and software partners. With APIM, in addition to not exposing the AppID and AppSecret and production endpoint, I can create subscriptions for each integrator, better controlling the services that each one can interact with.
Thanks Marcelo! I’m actually also working on something with the APIM, with additional logging using an Event Hub to have better understanding of why something is going wrong in case the API returns an error.
Hi Adria. Came across your article and really helped a lot. I’m now looking at how I can integrate Dynamics to Azure APIM which hosts some internal APIs which are using OAuth2.0. So far using a PCF component is ok, however the API and its key are both exposed and triggered client / browser side. Looking to see how this can be implemented in Dynamically server-side.
Hi M,
I’m not sure if I completely understand your scenario, but if you need to connect APIM to an API that uses OAuth2.0 you should be able to do that without issues, either getting the token and using it in the APIM endpoint, or using policies to generate the token inside APIM and just do calls to APIM using the subscription key for example.
Thanks for your reply. The issue seems to be when configuring Dynamics Customer Service or Field Service to call one of our APIs using a PCF component the URL and API Client Credentials are exposed to the client browser in the client side JavaScript, I’m wondering if you have come across this, and if not, do you have an article or guide that would show how to achieve this? I’ve been looking but many examples don’t really explain how Dynamics can integrate with a corporate API using OAuth 2.0
I see. Well, I’m on the ERP side of Dynamics 365, but it still should be possible from CE/CS/FS to authenticate using OAuth2.0, but I don’t have the technical knowledge of how that can be done.