azureazure-resource-managerazure-bicepapim

Bicep: Conditionally deploy a resource based on existence of a nullable object parameter


I'm trying to write a bicep template that conditionally deploys an APIM Version Set if a nullable object parameter was supplied. This seemed like it should be fairly simple but, unfortunately, my attempt seems to be failing due to some nullability constraints.

Minimal repro below:

main.bicep

/* ---- Types ---- */
type apimVersionSetParam = {
  name: string
  displayName: string
  description: string
  versioningScheme: ('Header'|'Query'|'Segment')?
}

/* ---- Params ---- */
param apimServiceName string
param versionSet apimVersionSetParam? // <-- Nullable object param of type apimVersionSet

/* ---- Resources ---- */

resource apim_service 'Microsoft.ApiManagement/service@2022-08-01' existing = {
  name: apimServiceName
}

// This resource should only be created if the versionSet object param was supplied
resource apim_version_set 'Microsoft.ApiManagement/service/apiVersionSets@2021-08-01' = if (versionSet != null) {
  name: versionSet!.name
  parent: apim_service
  properties: {
    displayName: versionSet!.displayName
    description: versionSet!.description
    versioningScheme: versionSet!.?versioningScheme ?? 'Segment'
  }
}

main.bicepparam

using './main.bicep'

param apimServiceName = 'bst-iaz-apim-dev'

When I supply a valid versionSet parameter in the bicepparam file, the template works fine. However, when I omit the parameter (or explicitly set it to null) I get the following error:

InvalidTemplate - Deployment template validation failed: 'The template resource '[format('{0}/{1}', parameters('apimServiceName'), parameters('versionSet').name)]' at line '1' and column '727' is not valid: The language expression property 'name' can't be evaluated.. Please see https://aka.ms/arm-functions for usage details.'.

It seems that the properties of the nullable object parameter are being referenced despite the fact that the resource that references them should be excluded from the deployment due to the if statement.

Is there another way to achieve this?

[Edit: Corrected bicep template file name in params file]


Solution

  • I managed to work around this by removing the nullability of the object param and providing a dummy default value.

    param versionSet apimVersionSetParam = {
      name: 'dummy'
      displayName: ''
      description: ''
    }
    

    ... then in the condition, I check if the provided object is the dummy default object:

    resource apim_version_set 'Microsoft.ApiManagement/service/apiVersionSets@2021-08-01' = if (versionSet.name != 'dummy') {
       ...
    }
    

    I'm not a fan of this solution though. It relies on "magic" values that represent the absence of the parameter when null would be a much more natural way to express that.

    I'll leave this answer for a few days before accepting it. Hopefully someone else will come up with a better solution before then :)