Bicep | Prevent a Nasty Refactor with Function Namespaces

Posted by Andrew Wilson on Monday, May 27, 2024

Problem Space

There have been few times where I have landed into this particular predicament whereby either by my own doing or through the use of another’s code base, a deep nested or thoroughly utilised (parameter/variable/or other defined item) has been created with the same name as a Bicep function. As by Murphy’s law, its only once you have reached this point of no return that you realise that your items name conflicts.

Now if you are like many in your unawares, your thoughts and actions will conclude to a singular one of ’that sucks… followed by a nasty refactor'.

Solution - Namespaces

Namespaces are a declarative scope in which identifiers such as the names of types, functions, and variables can be declared. These namespaces are used to organise code into logical groups and to prevent name collisions such as the one you are currently experiencing.

Thankfully, in Bicep there are two namespaces where all functions are split, az and sys.

  • az | Contains functions that are specific to an Azure deployment such as:
    • deployment
    • environment
    • resourceGroup
    • subscription
  • sys | Contains functions that are used to construct values, and decorators for parameters and resource loops. This includes but is not limited to:
    • [Array] concat
    • [File] loadJsonContent
    • [Lambda] filter
    • [Logical] bool
    • [Numeric] int
    • [String] contains

To make use of these namespaces, simply add the namespace identifier in front of the function. The example below shows a real world example of this issue where a parameter name ‘environment’ has been extensively utilised in this template and many others. This particular template is being used to deploy an AuthProvider in API Management, and the author wishes to utilise the environment function for the authentication.loginEndpoint. Without the use of the az namespace, the environment parameter would need to be refactored both in this template and wider templates for consistency.


/******************************************
Bicep Template: Function Namespace Example
Author: Andrew Wilson
******************************************/

targetScope = 'resourceGroup'

// ** Parameters **
// ****************

@description('The environment to deploy the resources to.')
@allowed([
  'dev'
  'test'
  'prod'
])
param environment string = 'dev'

...

// ** Variables **
// ***************

var ApiManagementName = toLower('apim-${projectName}-${environment}-${location}')

// ** Resources **
// ***************

...

// Create a new Auth Provider in APIM Credential Manager
resource AuthorizationProvider 'Microsoft.ApiManagement/service/authorizationProviders@2023-05-01-preview' = {
  ...
  properties: {
    ...
    oauth2: {
      ...
      grantTypes: {
        clientCredentials: {
          loginUri: az.environment().authentication.loginEndpoint
        }
      }
    }
  }
}

As always, have a play, and hope this helps.