Skip to content

Commit 60103f1

Browse files
authored
Add example for @Validate() decorator
1 parent f1c6015 commit 60103f1

File tree

4 files changed

+158
-0
lines changed

4 files changed

+158
-0
lines changed

bicep-examples/validate/README.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Azure Bicep - Validate Decorator
2+
3+
## Introduction
4+
5+
The `@validate()` decorator in Azure Bicep allows you to add custom validation logic to your parameters. This enables you to enforce complex constraints that go beyond basic type checking, catching configuration errors at deployment time with clear error messages.
6+
7+
This feature was released in [Bicep v0.32](https://github.com/Azure/bicep/releases/tag/v0.32.4) as an experimental feature.
8+
9+
## 📃 Benefits of the Validate Decorator
10+
11+
**Custom Validation**: Define complex validation rules using lambda expressions that return true or false.
12+
13+
**Clear Error Messages**: Validation errors include your custom message, making it easy to understand what went wrong.
14+
15+
**ARM-Level Enforcement**: Validation is enforced by Azure Resource Manager at deployment time, ensuring invalid configurations are rejected before resources are created.
16+
17+
## ⚗️ Enabling the Experimental Feature
18+
19+
The `@validate()` decorator is currently an experimental feature. To enable it, add the following to your `bicepconfig.json` file:
20+
21+
```json
22+
{
23+
"experimentalFeaturesEnabled": {
24+
"userDefinedConstraints": true
25+
}
26+
}
27+
```
28+
29+
## Example
30+
31+
In this example, the `@validate()` decorator uses a lambda expression to enforce that a CORS allowed origin FQDN does not contain protocol prefixes and is a valid domain format. The template then prepends `https://` to the validated FQDN when configuring the Storage Account CORS rules.
32+
33+
```bicep
34+
@description('Allowed origin FQDN for CORS. Must not contain https:// or http:// prefix.')
35+
@validate(
36+
x => !contains(x, 'https://') && !contains(x, 'http://') && contains(x, '.'),
37+
'The allowed origin FQDN must not contain "https://" or "http://" prefix and must be a valid domain name.'
38+
)
39+
param allowedOriginFqdn string
40+
```
41+
42+
The lambda syntax `x => expression` allows you to reference the parameter value within the validation expression. You can combine multiple conditions using logical operators like `&&` (and) and `||` (or).
43+
44+
> [!IMPORTANT]
45+
> The `@validate()` decorator is enforced at **ARM deployment time**, not at Bicep compile time. This means you need to deploy the template to see validation errors. If you want alternative options ahead of ARM engine deployment, look at the Bicep Test Framework and the `fail()` function.
46+
47+
### Validation Error Example
48+
49+
If you were to deploy with an invalid value like `https://app.contoso.com`, ARM would reject the deployment with an error similar to:
50+
51+
```plaintext
52+
{"code": "InvalidTemplate", "message": "Deployment template validation failed: The template parameter 'allowedOriginFqdn' failed validation. The allowed origin FQDN must not contain \"https://\" or \"http://\" prefix and must be a valid domain name."}
53+
```
54+
55+
This enables authors to define meaningful validation messages that surface during deployment, providing clear guidance on how to resolve the issue.
56+
57+
## 🚀 Deployment
58+
59+
> [!NOTE]
60+
> You need to have a resource group deployed before trying this out.
61+
62+
In Visual Studio Code open a terminal and run:
63+
64+
CLI
65+
66+
```bash
67+
az login
68+
az account set --subscription 'subscription name or id'
69+
az deployment group create -g 'your-rg' --confirm-with-what-if -f './main.bicep' -p 'main.bicepparam'
70+
```
71+
72+
or PowerShell
73+
74+
```powershell
75+
Connect-AzAccount
76+
Set-AzContext -Subscription "subscription name or id"
77+
New-AzResourceGroupDeployment -Confirm -ResourceGroup "your-rg" -TemplateFile "main.bicep" -TemplateParameterFile "main.bicepparam"
78+
```
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
// See https://aka.ms/bicep/config for more information on Bicep configuration options
3+
// Press CTRL+SPACE at any location to see Intellisense suggestions
4+
"analyzers": {
5+
"core": {
6+
"rules": {
7+
"no-unused-params": {
8+
"level": "warning"
9+
}
10+
}
11+
}
12+
},
13+
"experimentalFeaturesEnabled": {
14+
"userDefinedConstraints": true
15+
}
16+
}

bicep-examples/validate/main.bicep

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Rios Engineer - Bicep Validate Decorator
2+
targetScope = 'resourceGroup'
3+
4+
// Parameters
5+
@description('Deployment location for resources.')
6+
param location string = resourceGroup().location
7+
8+
// Parameters with validate decorator
9+
@description('Allowed origin FQDN for CORS. Must not contain https:// or http:// prefix.')
10+
@validate(
11+
x => !contains(x, 'https://') && !contains(x, 'http://') && contains(x, '.'),
12+
'The allowed origin FQDN must not contain "https://" or "http://" prefix and must be a valid domain name.'
13+
)
14+
param allowedOriginFqdn string
15+
16+
// Resources
17+
resource storageAccount 'Microsoft.Storage/storageAccounts@2024-01-01' = {
18+
name: 'st${uniqueString(resourceGroup().id)}'
19+
location: location
20+
sku: {
21+
name: 'Standard_LRS'
22+
}
23+
kind: 'StorageV2'
24+
properties: {
25+
minimumTlsVersion: 'TLS1_2'
26+
supportsHttpsTrafficOnly: true
27+
}
28+
}
29+
30+
resource blobService 'Microsoft.Storage/storageAccounts/blobServices@2024-01-01' = {
31+
parent: storageAccount
32+
name: 'default'
33+
properties: {
34+
cors: {
35+
corsRules: [
36+
{
37+
allowedOrigins: [
38+
'https://${allowedOriginFqdn}'
39+
]
40+
allowedMethods: [
41+
'GET'
42+
]
43+
allowedHeaders: [
44+
'*'
45+
]
46+
exposedHeaders: [
47+
'*'
48+
]
49+
maxAgeInSeconds: 3600
50+
}
51+
]
52+
}
53+
}
54+
}
55+
56+
// Outputs
57+
@description('The name of the storage account.')
58+
output storageAccountName string = storageAccount.name
59+
60+
@description('The allowed origin configured for CORS.')
61+
output allowedOrigin string = 'https://${allowedOriginFqdn}'
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
using './main.bicep'
2+
3+
param allowedOriginFqdn = 'app.contoso.com'

0 commit comments

Comments
 (0)