In past few articles, we have been discussing about Azure Bicep. In this article, we are going to talk about basic structure of a bicep file.
What does it mean to be a declarative ?
We know that the language bicep is said to be declarative. What does it mean ?
A language can be either declarative or imperative. Generally speaking, most of the developers may have used one of the imperative languages already. An imperative language is language in which we need to specify how something should be done. Each and every step must be specified in a specific order in order to make it work. Some common imperative languages are C, C++, Java, C#, etc.
In declarative languages, we do not need to specify how something should be done. We just need to specify what needs to be done.
Bicep is declarative language, meaning we do not need to specify how part, we just need to sepcify what we want to achieve.
Basic Structure of Bicep File
The code given below shows which elements can be generally seen in a bicep file.
- Target Scope
- Parameters
- Variables
- Resource
- Module (optional element)
- Output
The file format is taken from the documentation. We are going to have look at what these terms mean in the coming section
Target Scope
The first line in the code snippet given above, targetScope, defines the scope in which the services should be created. The allowed values are:
- resourceGroup – default value, used for resource group deployments.
- subscription – used for subscription deployments.
- managementGroup – used for management group deployments.
- tenant – used for tenant deployments.
Parameters
The parameters can be used to specify the values which can vary for different deployments. Some examples can be, environment name or let’s say region (geography or country) for which resources would be created or the SKU to specify the different sizes for different deployments.
We can also specify the default values in case the parameter value is not supplied.
A parameter can also have decorators. The parameter decorators can be used to describe the parameters and define the constraints (e.g. allowed values / ranges / etc.)
Variables
The variables can be used to represent some complex / computed values. For example, we may want to have application name and environment name in the app service instance name. So we can compute its name and declare a variable to hold the computed value. Then we can use that variable everytime we need to use the app service name.
Resource
This element defines the resource that we want to create. After the keyword resource, we can specify the symbolic name. This symbolic name we can refer later in the bicep code. In every resource element, the symbolic name is followed by the resource type and api version.
After that, there is a JSON object which specifies the properties needed for creating the resource, e.g. resource name, region, resource group, SKU, etc.
Module
This element allows referring other bicep files in the current one. That way, we can split the code into multiple files, making them more maintainable. We will try to learn more about this feature in subsequent posts. Also, this is an optional element, not always needed to be present in the bicep file.
Output
This section looks similar to the parameters and variables. The difference is, it contains the values which are supposed to be returned from the current operation. For example, after creating the storage account, we can return the storage account name, in case it is needed for the operations to be performed after the current operation is done.
Example
The code snippet given below shows an example bicep file. The file contains code to create storage account. High level overview of the script:
- There is no targetScope element, so it uses the default value,
resourceGroup
- It starts with @description to describe the parameter and @allowed to define the allowed values.
storageAccountType
is the parameter which is of type string and has a default value defined.location
andstorageAccountName
are other two parameters- the resource element defines a symbolic name
sa
- Then the output section defines two output values,
storageAccountName
andstorageAccountId
. For getting these two values, it uses the symbolic namesa
and the parameterstorageAccountName
.
I hope you find this information helpful. Let me know your thoughts.