Bicep Deployment of APIM API Operations

Bicep Deployment of APIM API Operations

Problem: Deploy your API Operations into APIM using BICEP

Existing Deployment: Simple deployment (no request or response definitions etc…)

  • Using a YAML driver:
  – template: ../apimanagement/cli/apis/APIM.AddApi.yaml
    parameters:
      azureServiceConnection: ${{ parameters.azureServiceConnection }}
      resourceGroupName: ‘$(coreResourceGroupName)’
      apiManagementServiceName: ‘$(coreApimInstance)’
      name: ‘oracle-erp-internal-api’
      displayName: ‘Oracle ERP Internal API’
      description: ‘Oracle Internal API for ERP’
      path: ‘/oracle/internal/erp’

– template: ../apimanagement/cli/apis/APIM.AddApi.Operation.yaml

    parameters:
      azureServiceConnection: ${{ parameters.azureServiceConnection }}
      resourceGroupName: ‘$(coreResourceGroupName)’
      apiManagementServiceName: ‘$(coreApimInstance)’
      apiName: ‘oracle-erp-internal-api’
      operationName: ‘getstandardreceipts’
      operationDisplayName: ‘GetStandardReceipts’
      operationDescription: ‘Gets Standard Receipts from Oracle’
      operationMethod: ‘GET’
      operationUrlTemplate: ‘/standardreceipts/{receiptNumber}’
      operationTemplateParameters:
        [
          {
            name: ‘receiptNumber’,
            description: ‘Number of the Standard Receipt In Oracle.’
          }
        ]
  • Which uses this YAML:
steps:
  – task: AzureCLI@2
    displayName: ‘Add API : ${{ parameters.name }}’
    inputs:
      azureSubscription: ${{ parameters.azureServiceConnection }}
      scriptType: bash
      scriptLocation: inlineScript
      inlineScript: |
        az deployment group create \
          –resource-group ‘${{ parameters.resourceGroupName }}’ \
          –name ‘iac.${{ parameters.apiManagementServiceName }}’ \
          –template-file ‘../sourceArtifact/resources/apimanagement/cli/apis/APIM.AddApi.bicep’ \
          –parameters ‘apimServiceName=${{ parameters.apiManagementServiceName }}’ \
          –parameters ‘name=${{ parameters.name }}’ \
          –parameters ‘displayName=${{ parameters.displayName }}’ \
          –parameters ‘apiDescription=${{ parameters.description }}’ \
          –parameters ‘path=${{ parameters.path }}’
  • And then this is the BICEP that is used to deploy the API:
resource apimServiceName_apiName ‘Microsoft.ApiManagement/service/apis@2019-12-01’ = {
  name: ‘${apimServiceName}/${name}’
  properties: {
    displayName: displayName
    description: apiDescription
    apiRevision: ‘1’
    subscriptionRequired: true
    path: path
    protocols: [
      ‘https’
    ]
    isCurrent: true
  }
}
This deployment was good and is maintainable up to a point, what about the request and response definitions and the example payloads etc…  As soon as we start introducing these then our API operations become trickier to deploy using BICEP resources.  We can however make use of the fact that an operation can be deployed using a Open API definition file, and this definition file can be exported directly from APIM once you have completed your configuration in the Azure Portal.

New Deployment: Using an Open API Definition File

  • Use the Azure Portal to develop and configure you APIs and operations
  • Export the API to one of the definition standards – I used OpenAPI v3 (JSON)

  • The API contains schemas and definitions etc… e.g.

  • [IMPORTANT STEP] Compress and flatten the OpenAPI definition export and added the file to my repos workspace
If you do not compress the JSON, you may end up wasting 12 hours like I did trying to work out what I had done wrong!
This is the error you would see in the pipeline deployment:
{
   “error”: {
      “code”: “DeploymentFailed”,
      “details”: [
         {
            “code”: “ValidationError”,
            “details”: [
               {
                  “code”: “ValidationError”,
                  “message”: “Parsing error(s): (Lin: 1, Col: 0, Chr: 1) – (Lin: 1, Col: 0, Chr: 1): While parsing a node, did not find expected node content.“,
                  “target”: “representation”
               },
               {
                  “code”: “ValidationError”,
                  “message”: “Parsing error(s): The input OpenAPI file is not valid for the OpenAPI specification https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md (schema https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v3.0/schema.yaml).”,
                  “target”: “representation”
               }
            ],
            “message”: “One or more fields contain incorrect values:”
         }
      ],
      “message”: “At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-deployment-operations for usage details.”,
      “target”: “/subscriptions/1234567a-8bc9-1234-d123-ef1g23h4i56j/resourceGroups/rg-wpk-esb-dev-core-uks-01/providers/Microsoft.Resources/deployments/iac.apim-wpk-esb-dev-core-uks-01”
   },
   “status”: “Failed”
}
  • The generation of the API and it’s separate operation BICEP generations can be replaced with the following YAML and BICEP commands:
  – task: PowerShell@2
    name: getERPDefinitionContentTest
    displayName: ‘Load File Content – Oracle ERP Internal API’
    inputs:
      targetType: ‘inline’
      script: |
        $content = Get-Content -Path “../sourceArtifact/resources/apimanagement/resources/Oracle ERP Internal API.openapi+json.json” -Raw
        echo $content
        Write-Output “##vso[task.setvariable variable=fileContent;isoutput=true]$content”
  – template: ../apimanagement/cli/apis/APIM.AddApiFromDefinition.yaml
    parameters:
      azureServiceConnection: ${{ parameters.azureServiceConnection }}
      resourceGroupName: ‘$(coreResourceGroupName)’
      apiManagementServiceName: ‘$(coreApimInstance)’
      name: ‘oracle-erp-internal-api’
      definitionFormat: ‘openapi+json’
      definitionContent: ‘$(getERPDefinitionContentTest.fileContent)’
      apiPath: ‘oracle/internal/erp’
The BICEP to use the OpenAPI definition looks like this:
resource apimServiceName_apiName ‘Microsoft.ApiManagement/service/apis@2023-09-01-preview’ = {
  name: ‘${apimServiceName}/${name}’
  properties: {
    format: definitionFormat
    value: definitionContent
    path: apiPath
  }
}

The definitions will appear here in the Azure Portal, and the everything will be configured correctly:

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *