azureazure-bicep

Azure APIM Integration with Function App fails using Bicep


We are trying to automate the deployment of Azure Function app with Azure API Management so that when there is a schema change, we don't have to manually update the APIM with the functionApp schema changes. Our API Management and Function App are inside different resource groups, but inside the same subscription. I have a main.bicep file withe following relevant parts.

targetScope = 'resourceGroup'

parameter definitions

Modules defined inside the bicep file like this

module functionapp 'modules/funcapp.bicep' = {

  name: 'funappDeploy'

  params: {

    tags: tags

    location: location

    application: application

    environment: environment

    instrumentationKey: appinsight.outputs.instrumentationKey

    storageAccountName: storageaccount.outputs.storageAccountName

    functionSubNetId: networking.outputs.functionSubnetId

    appInsightsConSting: appinsight.outputs.appInsightsConSting
 }
}

And my problematic api management definition below inside the main.bicep:

module apimanagement 'modules/apimanagement.bicep' = {

  name: 'apimdeploy'

  params: {
    application: application
    environment: environment
  }
}

API Management resource already exists, and API's including my relevant API is deployed inside. This was done early without automation.

And here is my apimanagement.bicep:

targetScope = 'resourceGroup'

param environment string
param application string = 'gcob-ncino'

var apimName = 'apim-rxx-${application}-${environment}'
var resourceGroupName = 'rg-rxx-apim-${application}-${environment}'

resource apiManagement 'Microsoft.ApiManagement/service@2024-05-01' existing = {
  name: apimName
  scope: resourceGroup(resourceGroupName)
}

resource apimApi 'Microsoft.ApiManagement/service/apis@2024-05-01' = {
  name: 'yourApimApiName'
  parent: apiManagement

  properties: {
    name: 'risk-rating' // This is the API name within APIM
    path: '/' //  The base path for this API
    displayName: 'risk-rating'
  }
}

resource apimBackend 'Microsoft.ApiManagement/service/backends@2024-05-01' = {
  name: 'my-function-app'
  parent: apiManagement

  properties: {
    protocol: 'https' // Or https
    url: 'azfun-my-dev.azurewebsites.net'
  }
}

resource apimApiBackendLink 'Microsoft.ApiManagement/service/apis/backends@2021-08-01' = {

  name: 'my-function-app-link'
  parent: apimApi

  properties: {
    backendId: apimBackend.id
  }
}

While deploying through the Azure DevOps, I see this error in the pipeline:

A resource's computed scope must match that of the Bicep file for it to be deployable. This resource's scope is computed from the "scope" property value assigned to ancestor resource "apiManagement". You must use modules to deploy resources to a different scope. [https://aka.ms/bicep/core-diagnostics#BCP165]

Can someone suggest how to fix this problem?

Thanks DD


Solution

  • The error you’re encountering is BCP165 because your apimanagement.bicep file sets a resourceGroup(resourceGroupName) scope for an existing resource (apiManagement), but you're deploying it from a Bicep file that already targets a different resource group.

    To resolve the issue, split the logic into separate modules and use scoped deployments. You can create a separate Bicep module for all API Management operations (e.g., apim-api.bicep) and deploy that module with the correct scope, targeting the resource group where the API Management instance exists.

    main.bicep

    targetScope = 'subscription'
    
    param location string = 'eastus'
    
    module funcappModule './modules/funcapp.bicep' = {
      name: 'deployFuncApp'
      scope: resourceGroup('rg-functions')
      params: {
        location: location
        functionAppName: 'func-demo-lab'
        storageAccountName: 'funcdemosa123'
      }
    }
    
    module apimApiModule './modules/apim-api.bicep' = {
      name: 'deployApimApi'
      scope: resourceGroup('rg-apim')
      params: {
        apimName: 'apim-demo-lab1'
        apiName: 'lab-api'
        functionAppUrl: funcappModule.outputs.functionAppUrl
        backendName: 'lab-api-backend'
      }
    }
    

    modules/apim-api.bicep

    param apimName string
    param apiName string
    param functionAppUrl string
    
    resource apim 'Microsoft.ApiManagement/service@2021-08-01' existing = {
      name: apimName
    }
    
    resource backend 'Microsoft.ApiManagement/service/backends@2021-08-01' = {
      name: 'functionapp-backend'
      parent: apim
      properties: {
        protocol: 'https'
        url: functionAppUrl
      }
    }
    
    resource api 'Microsoft.ApiManagement/service/apis@2021-08-01' = {
      name: apiName
      parent: apim
      properties: {
        displayName: apiName
        path: apiName
        protocols: [ 'https' ]
      }
    }
    
    resource apiBackend 'Microsoft.ApiManagement/service/apis/backends@2021-08-01' = {
      name: 'functionapp-backend-link'
      parent: api
      properties: {
        backendId: backend.id
      }
    }
    

    modules/funcapp.bicep

    param location string
    param functionAppName string
    param storageAccountName string
    
    resource sa 'Microsoft.Storage/storageAccounts@2022-09-01' = {
      name: storageAccountName
      location: location
      sku: { name: 'Standard_LRS' }
      kind: 'StorageV2'
    }
    
    resource app 'Microsoft.Web/sites@2022-03-01' = {
      name: functionAppName
      location: location
      kind: 'functionapp'
      properties: {
        serverFarmId: ''
        siteConfig: {
          appSettings: [
            {
              name: 'AzureWebJobsStorage'
              value: sa.properties.primaryEndpoints.blob
            }
          ]
        }
      }
    }
    output functionAppUrl string = 'https://${app.name}.azurewebsites.net'
    

    After running the code , The backend lab-api-backend is registered and points to the Function App URL and The API lab-api is listed under the APIs section in APIM

    Output:

    enter image description here