Connect your Java function to Azure Storage

Azure Functions lets you connect Azure services and other resources to functions without having to write your own integration code. These bindings, which represent both input and output, are declared within the function definition. Data from bindings is provided to the function as parameters. A trigger is a special type of input binding. Although a function has only one trigger, it can have multiple input and output bindings. To learn more, see Azure Functions triggers and bindings concepts.

This article shows you how to integrate the function you created in the previous quickstart article with an Azure Storage queue. The output binding that you add to this function writes data from an HTTP request to a message in the queue.

Most bindings require a stored connection string that Functions uses to access the bound service. To make this connection easier, you use the Storage account that you created with your function app. The connection to this account is already stored in an app setting named AzureWebJobsStorage.

Prerequisites

Before you start this article, complete the steps in part 1 of the Java quickstart.

Download the function app settings

You've already created a function app in Azure, along with the required Storage account. The connection string for this account is stored securely in app settings in Azure. In this article, you write messages to a Storage queue in the same account. To connect to your Storage account when running the function locally, you must download app settings to the local.settings.json file.

From the root of the project, run the following Azure Functions Core Tools command to download settings to local.settings.json, replacing <APP_NAME> with the name of your function app from the previous article:

func azure functionapp fetch-app-settings <APP_NAME>

You might need to sign in to your Azure account.

Important

This command overwrites any existing settings with values from your function app in Azure.

Because it contains secrets, the local.settings.json file never gets published, and it should be excluded from source control.

You need the value AzureWebJobsStorage, which is the Storage account connection string. You use this connection to verify that the output binding works as expected.

Enable extension bundles

The easiest way to install binding extensions is to enable extension bundles. When you enable bundles, a predefined set of extension packages is automatically installed.

To enable extension bundles, open the host.json file and update its contents to match the following code:

{
    "version": "2.0",
    "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[1.*, 2.0.0)"
    }
}

You can now add the Storage output binding to your project.

Add an output binding

In a Java project, the bindings are defined as binding annotations on the function method. The function.json file is then autogenerated based on these annotations.

Browse to the location of your function code under src/main/java, open the Function.java project file, and add the following parameter to the run method definition:

@QueueOutput(name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage") OutputBinding<String> msg

The msg parameter is an OutputBinding<T> type, which represents a collection of strings that are written as messages to an output binding when the function completes. In this case, the output is a storage queue named outqueue. The connection string for the Storage account is set by the connection method. Rather than the connection string itself, you pass the application setting that contains the Storage account connection string.

The run method definition should now look like the following example:

@FunctionName("HttpTrigger-Java")
public HttpResponseMessage run(
        @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION)  
        HttpRequestMessage<Optional<String>> request, 
        @QueueOutput(name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage") 
        OutputBinding<String> msg, final ExecutionContext context) {
    ...
}

Add code that uses the output binding

Now, you can use the new msg parameter to write to the output binding from your function code. Add the following line of code before the success response to add the value of name to the msg output binding.

msg.setValue(name);

When you use an output binding, you don't have to use the Azure Storage SDK code for authentication, getting a queue reference, or writing data. The Functions runtime and queue output binding do those tasks for you.

Your run method should now look like the following example:

@FunctionName("HttpTrigger-Java")
public HttpResponseMessage run(
        @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION) HttpRequestMessage<Optional<String>> request, 
        @QueueOutput(name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage") 
        OutputBinding<String> msg, final ExecutionContext context) {
    context.getLogger().info("Java HTTP trigger processed a request.");

    // Parse query parameter
    String query = request.getQueryParameters().get("name");
    String name = request.getBody().orElse(query);

    if (name == null) {
        return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build();
    } else {
        // Write the name to the message queue. 
        msg.setValue(name);

        return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
    }
}

Update the tests

Because the archetype also creates a set of tests, you need to update these tests to handle the new msg parameter in the run method signature.

Browse to the location of your test code under src/test/java, open the Function.java project file, and replace the line of code under //Invoke with the following code.

@SuppressWarnings("unchecked")
final OutputBinding<String> msg = (OutputBinding<String>)mock(OutputBinding.class);

// Invoke
final HttpResponseMessage ret = new Function().run(req, msg, context);

You're now ready to try out the new output binding locally.

Run the function locally

As before, use the following command to build the project and start the Functions runtime locally:

mvn clean package 
mvn azure-functions:run

Note

Because you enabled extension bundles in the host.json, the Storage binding extension was downloaded and installed for you during startup, along with the other Microsoft binding extensions.

As before, trigger the function from the command line using cURL in a new terminal window:

curl -w "\n" http://localhost:7071/api/HttpTrigger-Java --data AzureFunctions

This time, the output binding also creates a queue named outqueue in your Storage account and adds a message with this same string.

Next, you use the Azure CLI to view the new queue and verify that a message was added. You can also view your queue by using the Microsoft Azure Storage Explorer or in the Azure portal.

Set the Storage account connection

Open the local.settings.json file and copy the value of AzureWebJobsStorage, which is the Storage account connection string. Set the AZURE_STORAGE_CONNECTION_STRING environment variable to the connection string by using this Bash command:

AZURE_STORAGE_CONNECTION_STRING="<STORAGE_CONNECTION_STRING>"

When you set the connection string in the AZURE_STORAGE_CONNECTION_STRING environment variable, you can access your Storage account without having to provide authentication each time.

Query the Storage queue

You can use the az storage queue list command to view the Storage queues in your account, as in the following example:

az storage queue list --output tsv

The output from this command includes a queue named outqueue, which is the queue that was created when the function ran.

Next, use the az storage message peek command to view the messages in this queue, as in this example:

echo `echo $(az storage message peek --queue-name outqueue -o tsv --query '[].{Message:content}') | base64 --decode`

The string returned should be the same as the message you sent to test the function.

Note

The previous example decodes the returned string from base64. This is because the Queue storage bindings write to and read from Azure Storage as base64 strings.

Redeploy the project

To update your published app, run the following command again:

mvn azure-functions:deploy

Again, you can use cURL to test the deployed function. As before, pass the value AzureFunctions in the body of the POST request to the URL, as in this example:

curl -w "\n" https://fabrikam-functions-20190929094703749.azurewebsites.net/api/HttpTrigger-Java?code=zYRohsTwBlZ68YF.... --data AzureFunctions

You can examine the Storage queue message again to verify that the output binding generates a new message in the queue, as expected.

Clean up resources

Other quickstarts in this collection build upon this quickstart. If you plan to continue on with subsequent quickstarts or with the tutorials, don't clean up the resources created in this quickstart. If you don't plan to continue, use the following command to delete all resources created in this quickstart:

az group delete --name myResourceGroup

Select y when prompted.

Next steps

You've updated your HTTP-triggered function to write data to a Storage queue. To learn more about developing Azure Functions with Java, see the Azure Functions Java developer guide and Azure Functions triggers and bindings. For examples of complete Function projects in Java, see the Java Functions samples.

Next, you should enable Application Insights monitoring for your function app: