How to Create an Azure API Management Instance using Bicep Lang via Azure DevOpsby@willvelida
717 reads
717 reads

How to Create an Azure API Management Instance using Bicep Lang via Azure DevOps

by Will VelidaJuly 11th, 2021
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Bicep is a domain-specific language that uses declarative syntax to deploy resources to Azure resources. It allows us to create consistent API gateways for back-end services using APIM. Using APIM, we can publish APIs and make them available for external and internal developers to consume. I'm working on a personal health application that has a bunch of APIs (Built using Azure Functions) that interacts with my data. To be consistent, I want to deploy APIM using IaC via Azure DevOps.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - How to Create an Azure API Management Instance using Bicep Lang via Azure DevOps
Will Velida HackerNoon profile picture


The more I use Bicep, the more I love it. This is what ARM Templates should have been. When it comes to IaC, I usually use Terraform. It's the IaC tool we used at my last gig and I like that it has support for multiple clouds.

However, I've recently changed jobs and I'm finding that I'm using ARM templates more. With this in mind, I've been wanting to learn Bicep and use it in my own personal projects so when the day comes that I have to convert ARM templates to Bicep code, I'll be prepared 😂

Coming back to this article, I'm working on a personal health application that has a bunch of APIs (Built using Azure Functions ⚡) that interacts with my data. Ideally, I'd like to integrate this within Azure API Management. I deploy these APIs using Azure DevOps so to be consistent, I want to deploy APIM using IaC via Azure DevOps.

I'm going to show you how we can provision an Azure API Management instance using Bicep code and then deploy it using Azure DevOps.

One thing to note before we get started is that of the time of writing, there are no officially supported tasks for Bicep in Azure DevOps. For Terraform and ARM templates, we can use tasks in DevOps to deploy our infrastructure. For this article, I've used some AZ CLI tasks to build and deploy my Bicep templates.

So if you're reading this in a future where we can use officially supported Bicep tasks in DevOps, just keep this caveat in mind 😊

What is Bicep Lang?

Bicep is a domain-specific language that uses declarative syntax to deploy Azure Resources. When we wrote ARM templates, we were essentially writing JSON to deploy resources to Azure. The syntax for this could get a little complex and for fancy stuff, we would need to write complicated expressions to get it working.

Bicep Lang reduces that complexity significantly. Bicep is a transparent abstraction over ARM templates and when we deploy Bicep templates, it comes with a CLI that transpiles the Bicep file into ARM template JSON.

As of v0.3, Bicep is supported by Microsoft and has 100% parity with ARM templates, meaning that you can start using it for production workloads!

If you want to learn more about Bicep, you can check out the documentation here:

What is API Management

API Management (APIM) allows us to create consistent API gateways for back-end services. Using APIM, we can publish APIs and make them available for external and internal developers to consume.

APIM is made up of:

  • The Gateway which is the endpoint that accepts API calls and routes them to the right backend, verifies API Keys, enforces usage quotas and rate limits etc.
  • The Azure Portal which allows to administer our API Program, define API schema, package APIs into products, set up policies etc.
  • The Developer Portal which serves as the main web presence for developers, providing them with API documentation, allowing them to try out APIs via an interactive console and create an account that they can use to subscribe to APIs.

If you want to dive a bit deeper into APIM, check out the documentation:

Writing our Bicep Code for API Management

Let's start writing our Bicep code! 💪 The best tool for writing Bicep code is Visual Studio Code. There's also an awesome extension that you can download that will help validate your Bicep code and provide intellisense:

For this tutorial, I'm not going to focus too much on the complicated aspects of APIM. I just want to provision a simple configuration to get started with.

From what I can see from the docs, it looks like I'll need the following properties:

  • Name (What the name of the APIM service will be)
  • Type (The Type of resource we'll be provisioning)
  • ApiVersion (The version of the ARM API that we will be using)
  • Properties (Properties of the APIM that we want to configure, mainly the Publisher Email and Name)
  • Location (where we will provision our APIM instance)
  • SKU (The SKU properties of our APIM instance)

You can see the full reference for the APIM template here:

With the above properties in mind, we can write the following Bicep code:

param apimName string
param apimLocation string
param publisherName string
param publisherEmail string

resource myhealthapim 'Microsoft.ApiManagement/service@2019-12-01' = {
  name: apimName
  location: apimLocation
  sku: {
    name: 'Developer'
    capacity: 1
  properties: {
    publisherEmail: publisherEmail
    publisherName: publisherName

As you can see, I've used some parameters for some of the configuration values for my APIM instance. Let's discuss what these are in Bicep.

Using Parameters

In Bicep, we can use parameters to provide information to our Bicep templates when we deploy them. This allows us to make our Bicep templates reusable.

In the code above, we declared our parameters using the param keyword. Here's an example:

param parameterName string
  • param - indicates to Bicep that we are using a parameter
  • parameterName - the name of our parameter
  • string - refers to the type of the parameter

We can provide parameters through files. Parameter files are created using JSON. If we are deploying resources to multiple environments, we can create a parameter file for each environment and provided different values depending on the environment.

For this tutorial, I've created the following file.

    "$schema": "",
    "contentVersion": "",
    "parameters": {
        "apimName": {
            "value": "myhealthapiportal"
        "apimLocation": {
            "value": "australiaeast"
        "publisherName": {
            "value": "MyHealth API Portal"
        "publisherEmail": {
            "value": "[email protected]"

If you want to learn how parameters in Bicep, check out this Learn course:

Creating a Service Connection for Azure DevOps

In order to deploy our Bicep template, we'll need a Service Connection in DevOps that's authorized to deploy resources to Azure.

If you need to set this up, check out the following documentation:

Creating and running our Release Pipeline

Now that I have my Bicep template and parameter file, we can start to create our release pipeline.

I've kinda shot myself in the foot here. I have a uber-repo that I use for all of my IaC code that I've written to deploy resources to Azure. So for this tutorial, I'll be using the classic Release pipeline rather than YAML.

For this release, I used the following tasks:


Let's go through each task.

For our Copy Files task, I'm just copying the files from my GitHub artifact into the Default Working Directory on my build agent.


We'll use files in our target directory to run Bicep commands from.

Let's take a look at our first Azure CLI task:


Here, we are running the following az cli command

az bicep build --file "$env:SYSTEM_DEFAULTWORKINGDIRECTORY/main.bicep"

Here, we are building our bicep file. We can do this to build the ARM template that would be created by the bicep file, which could be used to run automated tests against, or for adding it to template specification, which can be shared with other users in our team.

To reference our Build file in the command, I'm using our System Default Working Directory as an environment. This is the folder that we copied our files to before. We can access variables in our release pipelines to transport and exchange data throughout our release pipelines:

Now let's move onto our final task, where we will be deploying our Bicep template:


In this AZ CLI task, we're running the following commands

az group create -l australiaeast -n myhealthapiportal-rg
az deployment group create --template-file "$env:SYSTEM_DEFAULTWORKINGDIRECTORY/main.bicep" --parameters "$env:SYSTEM_DEFAULTWORKINGDIRECTORY/main.parameters.json" --resource-group myhealthapiportal-rg

In our first command, we're creating a resource group in Azure called myhealthapiportal-rg to deploy our APIM instance to.

In our second command, we are creating a deployment at the subscription scope, using our main.bicep file as the template that we want to deploy and our main.parameters.json file as the parameters we will use for this deployment. I've also hard coded the resource group that I created earlier that I want to deploy our APIM resource to.

With this all set up, we can now run our release pipeline and it should deploy our APIM instance to Azure


Verifying that we deployed to Azure:


This took me a lot of goes, mainly messing about with the AZ CLI commands and getting them to point at our files.

Another thing to note is that I managed to deploy APIM the first time, but the deployment task took over an hour and failed, even though the deployment was successful when I went into my Azure portal.

Want to learn more?

Thanks for reading this article. At the time of writing, there are no official tasks for Bicep in Azure DevOps, so what I've done here to get this going is a bit of a hack, but it works.

If you want to learn more about Bicep, I recommend checking out the following resources from Microsoft Learn:

Hopefully you found this article useful! As always, if you have any questions, feel free to comment below or ask me on Twitter!

Happy Coding! 💻👨‍💻👩‍💻