Contract Deployment Automation for Azure API Management integration with PowerApps

Lili Xu
5 min readJan 7, 2022

This post explains the steps on automating the deployment of API contract to both Azure API Management and PowerApps Custom Connector.

As shown below, during the service development release, we expect API contract update(yellow) to be more frequent compared with infra configuration update(green). The main idea is to have the swagger contract file as the single source of truth and any update of it gets automatically deployed to both Azure APIM instance and PowerApps Custom Connector.

Although this post is mainly about automating the contract update(yellow), infra configuration update(green) could be automated together with corresponding ARM template files in the same DevOps pipeline.

Create New APIM Instance with OAuth2

In Azure portal, create a new APIM instance with default configuration.

Add OAuth2 Server Configuration

Detailed step refers here.

Disable Product Subscription Requirement

Go to APIs/Product/<Any Product>/settings, uncheck Requires subscription and save. This is to prevent the OAuth2 export issue to PowerApps. with Requires subscription checked, Subscription Key auth requirement on product level overrides the oauth2.0 setting in API level when exporting.

Configure API contract content

Define the API operations and response schemas.

Configure CORS Policy

Ss the API is going to be invoked from PowerApps site domain hidden iframe. It’s important to have CORS as the first policy applied in the policy xml setting. It should be the first element in <inbound>.

Configure API Security Setting

Uncheck Subscription required, Choose OAuth2.0 and select the OAuth2 server just configured.

Export Custom Connector

Select Power Platform blade and create a connector. Select the API that was just created and the target PowerApps Environment. OAuth2 Configuration is automatically populated during this process.

Create Solution

In PowerApps environment, the exported custom connector is expected to show up in Custom Connectors.

Go to Solutions and create a new solution. Edit the solution and Add existing-Other-Custom Connector.

Go back to Solutions list and export the solution as managed. The exported package is about to be downloaded in compressed format shortly.

Configure PowerApps Service Connection

  1. Create a new app registration PowerAppsSP on Azure Active Directory and assign Dynamics CRM delegated permisison with admin consent. Create a client secret for this new app registration PowerAppsSP. Detailed step could refer here.
  2. Create a PowerApps application user. On PowerApps Admin Center/Environments/<Environment Name>/Settings/User + Permissions/Application Users, choose PowerAppsSP from the list, and assign System Customizer role. Detailed step could refer here.
  3. Create PowerApps Service Connection on AzureDevOps. Server URL is the environment url {environment-id}.crm.dynamics.com, which could be found in PowerApps environment details page. Application ID and client Secret are from the AAD App.

Update Deployment Repository

Unzip the exported solution and upload to the repository.

Create a new ARM template file apim.json for Microsoft.ApiManagement/service/apis.

{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"service_name": {
"type": "String"
},
"swagger_json": {
"type": "String"
}
},
"resources" : [
{
"type": "Microsoft.ApiManagement/service/apis",
"apiVersion": "2021-08-01",
"name": "[concat(parameters('service_name'), '/dogeapiservice')]",
"dependsOn": [
"[resourceId('Microsoft.ApiManagement/service', parameters('service_name'))]"
],
"properties": {
"displayName": "DogeAPIService",
"apiRevision": "1",
"subscriptionRequired": false,
"value": "[parameters('swagger_json')]",
"format": "swagger-link-json",
"path": ""
}
}
]
}

Create a parameter file parameters.json under the same location with the file in blob location.

{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"service_name": {
"value": "test"
},
"swagger_json": {
"value": "https://{account-name}.blob.core.windows.net/new_5Fdogeapiservice_openapidefinition.json"
}
}
}

The repository file structure would look like this.

powersln/
Connector/
new_5Fdogeapiservice_connectionparameters.json
new_5Fdogeapiservice_iconblob.Png
new_5Fdogeapiservice_openapidefinition.json
new_5Fdogeapiservice_policytemplateinstances.json
[Content_Types].xml
customizations.xml
solution.xml
apim.json
parameters.json

Build Azure DevOps Pipeline

Create yaml file azure-pipelines.yml with following tasks defined using windows agent pool.

pool:  vmImage: windows-latest

1.Upload swagger contract to blob storage account.

- task: AzureFileCopy@4
inputs:
SourcePath: '$(Build.SourcesDirectory)/powersln/Connector/new_5Fdogeapiservice_openapidefinition.json'
azureSubscription: 'Visual Studio Enterprise(<subscription id>)'
Destination: 'AzureBlob'
storage: '<storage account>'
ContainerName: '<container name>'

2.Deploy APIM contract update with swagger content type that refers to the blob location.

- task: AzureResourceManagerTemplateDeployment@3
inputs:
deploymentScope: 'Resource Group'
azureResourceManagerConnection: 'Visual Studio Enterprise(<subscription id>)'
subscriptionId: '<subscription id>'
action: 'Create Or Update Resource Group'
resourceGroupName: 'test'
location: 'West US'
templateLocation: 'Linked artifact'
csmFile: '$(Build.SourcesDirectory)/apim.json'
csmParametersFile: '$(Build.SourcesDirectory)/parameters.json'
deploymentMode: 'Incremental'

3.Compress the zip file for PowerApps solution deployment.

- task: ArchiveFiles@2
inputs:
rootFolderOrFile: '$(Build.SourcesDirectory)/powersln'
includeRootFolder: false
archiveType: 'zip'
archiveFile: '$(Build.ArtifactStagingDirectory)/powersln.zip'
replaceExistingArchive: true

4.Install Power Platform Tool.

- task: microsoft-IsvExpTools.PowerPlatform-BuildTools.tool-installer.PowerPlatformToolInstaller@0
displayName: 'Power Platform Tool Installer'

5.Import Solution.

- task: PowerPlatformImportSolution@0
inputs:
authenticationType: 'PowerPlatformSPN'
PowerPlatformSPN: 'RCPower'
SolutionInputFile: '$(Build.ArtifactStagingDirectory)/powersln.zip'
AsyncOperation: false

Create new ADO pipeline from the yaml file. So far, we have completed all the setup.

Running the pipeline would apply the API contract change in swagger openAPI definition to both APIM instance and PowerApps Custom Connector.

--

--