Skip to main content

How to write Azure Functions in Scala - Basic Example

Introduction

Azure Functions are an easy and quick way of deploying code for specific functions like processing data or attending to HTTP requests.

As Azure Functions support Java, we can easily use that SDK to write our functions in Scala, in case that you need it.

Configuring the Scala Project

Create a new Scala project. I normally use maven with this archetype: net.alchim31.maven: scala-archetype-simple: 1.7 and then remove from the pom everything I don’t need.

Maven configuration

In this case, for writing an Azure Function, you need to have the following code in your pom:

  • Properties:
    • Scala version: here I'm using scala 2.12.12.

    • Java version: 1.8 in this case, but versions like 17 are also supported.

      I'm also using these properties section to define variables needed later for the deployment of the function to azure:

    • Azure Functions java library version: Check the latest version available here: Maven Repository: com.microsoft.azure.functions » azure-functions-java-library (mvnrepository.com)

    • Function App Name: Name of your function in azure.

    • Resource Group Name: Name of the resource group where you’re going to put the function.

    • App Service Plan: The name of the plan associated with the function.

    • Azure Region: Region in azure where your resources are deployed.

<properties>
<scala.version>2.12.12</scala.version>
<java.version>1.8</java.version>

<azure.functions.maven.plugin.version>1.22.0</azure.functions.maven.plugin.version>
<azure.functions.java.library.version>2.2.0</azure.functions.java.library.version>

<azure.functionAppName>function-name</azure.functionAppName>
<azure.resourceGroup>azure-resource-group-name</azure.resourceGroup>
<azure.appServicePlanName>azure-app-service-plan</azure.appServicePlanName>
<azure.region>azure-region</azure.region>
</properties>
  • Dependencies: add the azure functions library.
<dependencies>

.....

<dependency>
<groupId>com.microsoft.azure.functions</groupId>
<artifactId>azure-functions-java-library</artifactId>
<version>${azure.functions.java.library.version}</version>
</dependency>
  • Build: plugin configuration - In the build section, add your function configuration.
<build>
<plugins>
...
<plugin>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-functions-maven-plugin</artifactId>
<version>${azure.functions.maven.plugin.version}</version>
<configuration>

<!-- function app name -->
<appName>${azure.functionAppName}</appName>

<!-- function app resource group -->
<resourceGroup>${azure.resourceGroup}</resourceGroup>

<!-- function app service plan name -->
<appServicePlanName>${azure.appServicePlanName}</appServicePlanName>

<!-- function app region-->
<!-- refers https://github.com/microsoft/azure-maven-plugins/wiki/Azure-Functions:-Configuration-Details#supported-regions for all valid values -->
<region>${azure.region}</region>

<runtime>
<!-- runtime os, could be windows, linux or docker-->
<os>linux</os>
<javaVersion>8</javaVersion>
</runtime>
<appSettings>
<property>
<name>FUNCTIONS_EXTENSION_VERSION</name>
<value>~4</value>
</property>
</appSettings>
</configuration>
<executions>
<execution>
<id>package-functions</id>
<goals>
<goal>package</goal>
</goals>
</execution>
</executions>
</plugin>

</plugins>
</build>

Other files needed

You also need to add the following files to the root of your project:

picture de-300

  • host.json
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[3.*, 4.0.0)"
}
}
  • local.settings.json: for running the function locally.
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"FUNCTIONS_WORKER_RUNTIME": "java"
}
}

Writing the function’s code

Create a new class. Source file

package wiki.dataengineering

import com.microsoft.azure.functions.{ExecutionContext, HttpMethod, HttpRequestMessage, HttpResponseMessage, HttpStatus}
import com.microsoft.azure.functions.annotation.{AuthorizationLevel, FunctionName, HttpTrigger}

import java.util.Optional

class TestFunction {

@FunctionName("Test")
def run(@HttpTrigger (name = "req", methods = Array(HttpMethod.POST, HttpMethod.GET), authLevel = AuthorizationLevel.ANONYMOUS) request: HttpRequestMessage[Optional[String]], context: ExecutionContext): HttpResponseMessage = {

context.getLogger.info("Function executed")

context.getLogger.info(request.getHttpMethod.toString)
context.getLogger.info(request.getUri.toString)
context.getLogger.info(request.getBody.toString)

request.createResponseBuilder(HttpStatus.OK).body("It Works!").build()
}

}

In order to write your own, what you need to do is to create a function and add the @FunctionName("") decorator.

That run method can have any of the existing triggers available for azure Functions. (https://learn.microsoft.com/en-us/azure/azure-functions/functions-triggers-bindings?tabs=java#bindings-code-examples)

In this case, we're using an HTTP trigger that accepts POST and GET methods, and it can be accessed without authentication.

We have also specified that the input body will be a String.

Something really nice about this, It is that you can specify a scala class as your input, and the framework will automatically try to serialize the JSON body of the request (if there is one), to that class.

case class InputMessage (field1: String, field2: Int)

...

def run(@HttpTrigger (.... request: HttpRequestMessage[Optional[InputMessage]], context: ExecutionContext): HttpResponseMessage = {

With that “InputMessage” case class definition, the function will expect a body like this:

{
"field1": "test",
"field2": 1
}

Running the function locally

From a terminal or from Intellij’s integrated maven type:

mvn clean package

This will recompile the code and generate an artifact (a jar file) with the code.

picture de-800

If you want to run the function locally, run after the previous command the following:

mvn azure-functions:run

If it’s the first time you’re running it, it may give you the following error:

picture de-800

To fix it, simply follow that link and install the Azure Functions Core tools. If you’re using Intellij, you may need to close and open it again before you can use it.

Then you should be able to see the logs of your function:

picture de-800

You can use that URL to check if the function works as expected:

  • GET Request:

picture de-800

  • POST Request:

picture de-800

Defining multiple functions

In order to define multiple functions, you only need to write more classes following the same pattern, or add more methods with the FunctionName decorator:

picture de-300

They will all spin up when you deploy the code.

picture de-500

Deployment on Azure

If you have everything setup in the pom, as we indicated at the beginning of the post, deploying the azure function is as simply as running the following command.

mvn azure-functions:deploy

Code

You can find the code of this project here: https://github.com/data-engineering-content/azure-functions-scala