Insight Tech APAC Blog Logo

Leveraging User Defined Types & Lamda Functions

stephentulp
December 19, 2023

4 minutes to read

Bicep Advent Calendar

Introduction

Now that we have the Landing Zone deployed and getting more comfortable with the array of tools and features we have available to us, we can start to look at some of the more advanced features of Bicep. Today we will look at User-Defined Data Types and Lambda Functions.

User-Defined Data Types

User-defined types has recently gone GA and is a feature within Bicep that allows for the creation of custom complex objects within a Bicep template that can encapsulate related properties into a reusable element. Being able to define our own data types is a powerful feature that can help us simplify our Bicep code and make it more readable and maintainable.

The example below is an example of a storage account without using user-defined types.

param location string = resourceGroup().location
param storageAccountName string

@allowed([
  'Storage'
  'StorageV2'
])
param kind string = 'StorageV2'

@allowed([
  'Standard_LRS'
  'Standard_GRS'
])
param skuName string = 'Standard_GRS'

@allowed([
  'Premium'
  'Hot'
  'Cool'
])
param accessTier string = 'Hot'

resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
  name: storageAccountName
  location: location
  kind: kind
  sku: {
    name: skuName
  }
  properties: {
    accessTier: accessTier
  }
}

We can do this instead

param location string = resourceGroup().location

type kind = 'Storage' | 'StorageV2'
type skuName = 'Standard_LRS' | 'Standard_GRS'
type accessTier = 'Premium' | 'Hot' | 'Cool'

type storageAccountConfigType = {
  name: string
  sku: skuName
  kind: kind
  tier: accessTier
}

param storageAccountConfig storageAccountConfigType

resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
  name: storageAccountConfig.name
  location: location
  sku: {
    name: storageAccountConfig.sku
  }
  kind: storageAccountConfig.kind
  properties: {
    accessTier: storageAccountConfig.tier
  }
}

You can see how we are able to group together various parameters that make up the storage account into a single object. This makes it easier to read and understand what is being deployed. We can also reuse this object in other parts of the template.

Benefits of User-Defined Data Types

Some of the benefits of using user-defined types, include:

  • Reusability: User-defined types can be defined once and reused across multiple Bicep files or within the same file. This promotes code modularity and reduces duplication.
  • Abstraction: User-defined types provide a level of abstraction by allowing you to define custom data structures that align with your specific needs and inputs you are expecting.

Lambda Functions

Lambda expressions (or lambda functions) are blocks of code that can be passed as an argument, taking multiple parameters that are restricted to a single line of code.

In Bicep, lambda expression is in this format:

<lambda variable> => <expression>

Lets take a look at a couple of functions that may be useful, filter() and sort()

Filter

filter(inputArray, lambda expression)

This will filter an array with a custom filtering function. Lets take a look at an example.

var peoples = [
  {
    name: 'Stephen'
    age: 31
  }
  {
    name: 'Trent'
    age: 35
  }
  {
    name: 'Cam'
    age: 28
  }
  {
    name: 'Paul'
    age: 48
  }
]

output oldPeople array = filter(peoples, people => people.age >=31)

Based on this we would have Stephen, Trent and Paul in the oldPeople array.

Sort

sort(inputArray, lambda expression)

This sorts an array with a custom sort function. Lets take a look at an example.

var peoples = [
  {
    name: 'Stephen'
    age: 31
  }
  {
    name: 'Trent'
    age: 35
  }
  {
    name: 'Cam'
    age: 28
  }
  {
    name: 'Paul'
    age: 48
  }
]

output peopleByAge array = sort(peoples, (a, b) => a.age < b.age)

Based on this we would have Cam, Stephen, Trent and Paul in the peopleByAge array.

Conclusion

As you can see with these different function types and advanced features, you have a lot of control and options to make your Bicep templates more readable, maintainable and reusable. If the syntax or structure seems complicated at first, I suggest using some examples to get a better understanding of how this can be used within your templates.

In preview, User Defined Functions also builds on the extensibility of Bicep and allows you to create custom functions that can be used within your Bicep templates.

Further Reading