Azure Functions support for Node.js

Introduction

Azure Functions allow the execution of source code on the cloud. The execution can be set to be triggered by Azure events. Source code implementing a Node.js Azure Function contains a function.json file and an index.js file. These files are placed in the same directory and the name of the directory gives the name of the Azure Function. The index.js file contains a default export function with the source code that will be executed when the azure function is triggered.

Whenever an Azure Function is found in the analyzed source code, an Azure Function object is created with a callLink to the JavaScript handler function. Note that if the handler function is defined in a TypeScript file, this extension will create the Azure Function with a callLink to the TypeScript handler function only if the com.castoftware.typescript extension is used.

The azure function can be configured to be triggered or to interact with other Azure services. The following table lists the supported interactions:


trigger input output
Http (tick)

Service Bus (tick)
(tick)
Blob (tick) (tick) (tick)
CosmosDB (tick) (tick) (tick)
SignalR
(tick)

Detailed support for each of these interactions is given in the following sections.

Http trigger

When the bindings section of the function.json file contains one item of type “httpTrigger”, a NodeJS operation is created with a call link to the handler function. The URL is evaluated from the “route” value and the operation type is given by the “methods” value. When analyzing the following source code:

FooAzureFunction/function.json

{
  "bindings": [
    {
      "authLevel": "anonymous",
      "name": "req",
      "type": "httpTrigger",
      "direction": "in",
      "route": "foo/url",
      "methods": ["delete", "put"]
    }
}

the following result will be produced:

Azure Service Bus trigger and binding

  • When the bindings section of the function.json file contains one item of type “serviceBusTrigger”, a Service Bus Receiver is created with a call link to the Azure Function. The name of the queue is evaluated from the “name” value.
  • When the bindings section of the function.json file contains one item of type “serviceBus” with a direction “out”, a Service Bus Publisher is created with a call link from the handler function. The name of the queue is evaluated from the “name” value.

For example, when analyzing the following source code:

FooAzureFunction/function.json

{
"bindings": [
    {
      "queueName": "testqueuetrigger",
      "connection": "MyServiceBusConnection",
      "name": "myQueueItem",
      "type": "serviceBusTrigger",
      "direction": "in"
    },

    {
      "name": "outputSbQueue",
      "type": "serviceBus",
      "topicName": "testqueue",
      "connection": "MyServiceBusConnection",
      "direction": "out"
    }
]}

the following result will be produced:

Blob trigger and binding

  • When the bindings section of the function.json file contains one item of “type” “blobTrigger”, a property is added to the Azure Function object. That property (CAST_Azure_Function.blob_triggers) stores the name of the blob container which is evaluated from “path”. The Web Services Linker extension will then create a link to the Azure Function from all callers with a useInsert or useUpdate link of all blob containers matching that path. The callers may come from any CAST extension.
  • When the bindings section of the function.json file contains one item of type “blob” with a direction “in” (resp. “out”), a blob container is created with a useSelect (resp. useUpdate) link from the handler function to the blob container. The name of the container is given by the beginning of “path”.

For example, when analyzing the following source code:

FooAzureFunction/function.json

{
    "disabled": false,
    "bindings": [
        {
            "name": "myBlob",
            "type": "blobTrigger",
            "direction": "in",
            "path": "mycontainer/{name}",
            "connection":"MyStorageAccountAppSetting"
        },
        {
          "name": "myInputBlob",
          "type": "blob",
          "path": "samples-workitems-in/{queueTrigger}",
          "connection": "MyStorageConnectionAppSetting",
          "direction": "in"
        },
        {
          "name": "myOutputBlob",
          "type": "blob",
          "path": "samples-workitems-out/{queueTrigger}-Copy",
          "connection": "MyStorageConnectionAppSetting",
          "direction": "out"
        }
    ]
}

the following result will be produced:

CosmosDB trigger and binding

  • When the bindings section of the function.json file contains one item of “type” “cosmosDBTrigger”, a property is added to the azure function object. That property (CAST_Azure_Function.cosmosDB_triggers) stores the name of the CosmosDB database and collection which are evaluated from “databaseName” and “collectionName”. The Web Services Linker extension will then create a link to the Azure Function from all callers calling with a useInsert or useUpdate link a cosmosdb collection matching the collection name and database. The callers may come from any CAST extension.
  • When the bindings section of the function.json file contains one item of type “documentDB” or “cosmosDB” with a direction “in” (resp. “out”), a cosmosdb collection is created with a useSelect (resp. useUpdate) link from the handler function to the blob container. The name of the collection is given by “collectionName”. The parent of the collection is a CosmosDB database with the name taken from “databaseName”.

For example, when analyzing the following source code:

FooAzureFunction/function.json

{
    "disabled": false,
    "bindings": [
      {
          "type": "cosmosDBTrigger",
          "name": "documents",
          "direction": "in",
          "leaseCollectionName": "leases",
          "connectionStringSetting": "<connection-app-setting>",
          "databaseName": "MyDatabase",
          "collectionName": "MyCollectionTrigger",
          "createLeaseCollectionIfNotExists": true
      },
      {
          "name": "inputDocumentIn",
          "type": "documentDB",
          "databaseName": "MyDatabase",
          "collectionName": "MyCollectionIn",
          "id" : "{queueTrigger_payload_property}",
          "partitionKey": "{queueTrigger_payload_property}",
          "connection": "MyAccount_COSMOSDB",
          "direction": "in"
      },
      {
          "name": "inputDocumentOut",
          "type": "documentDB",
          "databaseName": "MyDatabase",
          "collectionName": "MyCollectionOut",
          "createIfNotExists": false,
          "partitionKey": "{queueTrigger_payload_property}",
          "connection": "MyAccount_COSMOSDB",
          "direction": "out"
      }
    ]
}

the following result will be produced:

Event Hubs trigger and output

  • When the bindings section of the function.json file contains one item of type “eventHubTrigger”, an Azure Event Hub Receiver is created with a call link to the handler function. The name of the event hub is evaluated from the “eventHubName” value.
  • When the bindings section of the function.json file contains one item of type “eventHub” with a direction “out”, a Azure Event Hub Publisher is created with a call link from the handler function. The name of the queue is evaluated from the “eventHubName” value.

For example, when analyzing the following source code:

FooAzureFunction/function.json

{
"bindings": [
    {
        "type": "eventHubTrigger",
        "name": "myEventHubMessage",
        "direction": "in",
        "eventHubName": "MyEventHub",
        "connection": "myEventHubReadConnectionAppSetting"
    },
    {
        "type": "eventHub",
        "name": "outputEventHubMessage",
        "eventHubName": "MyEventHubOutput",
        "connection": "MyEventHubSendAppSetting",
        "direction": "out"
    }
]
}

the following result will be produced:

SignalR trigger

When the bindings section of the function.json file contains one item of type “signalRTrigger”, a NodeJS SignalR Hub Method is created with a call link to the handler function. Its name is evaluated from the “event” value. It has a hub name property evaluated from the “hubName” value. For example, when analyzing the following source code:

FooAzureFunction/function.json

{
"bindings": [
      {
        "type": "signalRTrigger",
        "name": "invocation",
        "hubName": "SignalRTest",
        "category": "messages",
        "event": "testsignalrtrigger",
        "parameterNames": [
            "message"
        ],
        "direction": "in"
      }
]
}

the following result will be produced:

Durable functions

Durable functions allow an Azure Function to call another Azure Function. There are three kinds of durable functions:

  • the orchestrator function
  • the client function
  • the activity function

The startNew method from the “durable-function” client allow the client function to call an orchestrator function.  The callActivity method from the “durable-function” package allows calling an activity function. Whenever one of these method calls is found in a JavaScript source code, a call to Azure Function object is created. The name of the object is evaluated from the first argument of the call. If an Azure Function object with the same name exists, a call link from the call to the Azure Function to that matching Azure Function is created.

For example when analyzing the following source code:

index.js

const df = require("durable-functions");

module.exports = async function (context, req) {
    const client = df.getClient(context);
   
    const instanceId = await client.startNew("MyOrchestrator", undefined, req.body);
};

the following result will be produced:

Durable function client with HTTP trigger

It is common that a durable function client is triggered by an HTTP call and that with a proper URL any orchestrator function can be triggered. In this case, for each existing orchestrator azure function, an Operation with the corresponding URL is created with a callLink to a Call to Azure Function object to the orchestrator function.

For example when analyzing the following source code:

MyClientFunction/index.js

const df = require("durable-functions");

module.exports = async function (context, req) {
    const client = df.getClient(context);
    const instanceId = await client.startNew(req.params.functionName, undefined, req.body);
};

MyClientFunction/index.js

const df = require("durable-functions");

module.exports = async function (context, req) {
    const client = df.getClient(context);
    const instanceId = await client.startNew(req.params.functionName, undefined, req.body);
};

if your source code contains two orchestrator azure functions named Orchestrator and MyOtherOrchestrator, the following result will be produced: