Skip to content
Creating and Deploying Azure Function App for Dynamic Backend
todd-bernson-leadership

A serverless architecture is only complete with a dynamic backend capable of handling API requests and generating responses on demand. In this article, I’ll walk through setting up an Azure Function App using Terraform to handle dynamic requests, deploy Node.js code, and configure an HTTP trigger. This function app will be a fundamental part of my serverless web app, allowing us to serve dynamic content alongside the static assets served by Azure CDN.

Step 1: Configuring the Azure Function App with Terraform

The Azure Function App is built on top of a Linux-based service plan, configured with Node.js, and deployed in a way that allows it to serve requests over HTTPS. Let's go over the essential Terraform code for creating the Function App.

Terraform Code - Function App Configuration

This Terraform setup includes creating a function app, configuring a system-assigned identity, and setting up CORS to restrict access to specific origins. Here, I also define a storage account that will host the function code.

data "archive_file" "function_code" {
  type = "zip"

  output_path = "${path.module}/${local.function_code_directory}/${local.function_zip_file}"
  source_dir  = "${path.module}/${local.function_code_directory}/"

  excludes = ["*.zip"]
}

locals {
  app_function_os_type       = title(var.function_app_os_type)
  function_code_directory    = "function-code"
  function_zip_file          = "function_code.zip"
}

resource "azurerm_linux_function_app" "this" {
  name                = "${local.project}-functions"
  resource_group_name = azurerm_resource_group.this.name
  location            = azurerm_resource_group.this.location

  storage_account_name       = azurerm_storage_account.this.name
  storage_account_access_key = azurerm_storage_account.this.primary_access_key
  service_plan_id            = azurerm_service_plan.this.id

  identity {
    type = "SystemAssigned"
  }

  site_config {
    application_stack {
      node_version = "20"
    }

    cors {
      allowed_origins = [
        "https://${local.site_domain}"
      ]
    }
  }

  app_settings = {
    "WEBSITE_RUN_FROM_PACKAGE" = "${azurerm_storage_account.this.primary_blob_endpoint}${local.function_code_directory}/${local.function_zip_file}"
  }
}

This code configures a Linux-based function app with Node.js version 20 and restricts CORS to requests originating from the specified domain.

Screenshot Placeholder: Azure portal view showing the Function App setup, identity, and CORS settings.

Step 2: Creating the Service Plan and Role Assignment

I need a service plan to run my function app, and the function app requires access to the storage account where the function code will be hosted. The following Terraform code provisions these resources.

Terraform Code - Service Plan and Role Assignment

resource "azurerm_service_plan" "this" {
  name                = "${local.project}-service-plan"
  location            = azurerm_resource_group.this.location
  resource_group_name = azurerm_resource_group.this.name

  os_type  = local.app_function_os_type
  sku_name = "B1"
}

resource "azurerm_role_assignment" "function_storage_access" {
  scope                = azurerm_storage_account.this.id
  role_definition_name = "Storage Blob Data Reader"
  principal_id         = azurerm_linux_function_app.this.identity[0].principal_id
}

Screenshot Placeholder: Azure portal view of the service plan and role assignment configuration.

Step 3: Preparing and Uploading Function Code

My function code will be a simple Node.js app that returns a random fun fact. I archive the code and upload it to a storage blob for deployment.

Node.js Function Code - App.js

The following Node.js function, App.js, generates a random fun fact and sends it as a response.

module.exports = async function (context, req) {
    const facts = [
        "Bananas are berries, but strawberries aren't.",
        "A group of flamingos is called a 'flamboyance'.",
        "Octopuses have three hearts.",
        "Honey never spoils.",
        "A cow-bison hybrid is called a beefalo."
    ];

    const randomFact = facts[Math.floor(Math.random() * facts.length)];

    context.res = {
        body: randomFact
    };
};

Terraform Code - Uploading Function Code as a Blob

This code zips the function code and uploads it as a blob, setting it as the deployment package for the Function App.

resource "azurerm_storage_blob" "function_code" {
  name                   = local.function_zip_file
  content_md5            = data.archive_file.function_code.output_md5
  source                 = data.archive_file.function_code.output_path
  storage_account_name   = azurerm_storage_account.this.name
  storage_container_name = azurerm_storage_container.function_code.name
  type                   = "Block"
}

Screenshot Placeholder: Deployment view showing the uploaded function code blob in Azure Storage.

Step 4: Setting Up an HTTP Trigger

My function app uses an HTTP trigger to process requests and return responses. Once deployed, the function can be called via a simple HTTPS request.

Screenshot Placeholder: Azure Function App with HTTP trigger configured in the Azure portal.

With my Azure Function App in place, I now have a serverless backend capable of handling dynamic requests. This function app, combined with the CDN-hosted static assets, provides a seamless experience for users and demonstrates the power of serverless architectures.

Stay tuned for more in this series as I continue to dive into best practices, deployment techniques, and optimizations for building robust serverless applications on Azure.

Related Articles

Inter-Region WireGuard VPN in AWS

Read more

Making PDFs Searchable Using AWS Textract and CloudSearch

Read more

Slack AI Bot with AWS Bedrock Part 2

Read more

Contact Us

Achieve a competitive advantage through BSC data analytics and cloud solutions.

Contact Us