Azure Functions Node.js 開発者向けリファレンス

この参考文献では、JavaScriptとTypeScriptを用いてnpmパッケージを@azure/functions使ってAzure Functionsを開発する方法を扱います。 すべての言語で共有されているAzure Functionsの概念の一般的な概要については、Azure Functions developer referenceをご覧ください。

資源 Link
最初のJavaScript関数を作成します Visual Studio Code/CLI
最初のTypeScript関数を作成します Visual Studio Code/CLI
シナリオとサンプル JavaScript/TypeScript
API リファレンス @azure/functions Api

この記事は、ページ上部のセレクターに基づいた特定のプログラミングモデルバージョンのコンテンツを示しています。 選ぶバージョンは @azure/functions のNPMパッケージ版と一致しているはずです。 同じアプリ内でv3とv4の機能を混同することはできません。 package.jsonにパッケージがなければ、デフォルトはv3です。

プログラミング モデル

Azure Functions for Node.js は2つのプログラミングモデルバージョンをサポートしています。 新しいプロジェクトはv4を使うべきです。

特徴 V4(推奨) v3
地位 GA GA(メンテナンス)
@azure/functions パッケージ 4.x 3.x
関数の登録 コード中心(app.http()app.timer()) ファイルベース(function.json)
ファイル構造 フレキシブル 固定(各関数につき1つのフォルダ)
Functions ランタイムのバージョン 4.25+ 4.x
Node.js のバージョン 24.x、22.x 24.x、22.x

Node.js v4プログラミングモデルでは、関数をappから@azure/functionsオブジェクトを取り込み、トリガー固有のメソッドを呼び出して登録します。 関数はコード内で直接定義され、柔軟なファイル構造で提供されています。 すべての関数には実行を開始する単一の トリガー があり、また入力データの読み取りや出力データの書き込みを行う他のサービスへの宣言的接続である バインディングを持つこともできます。 詳細については 、「トリガーとバインディング」をご覧ください。

v4モデルでは、あなたは以下の通りです:

  • app.http()app.timer()app.storageQueue()などのトリガー固有の手法を用いてレジスタ機能を行います。
  • トリガー入力をハンドラーの最初の引数としてアクセスしてください(例: HttpRequest)。
  • ハンドラ関数から直接プライマリ出力を返します。
  • Blob Storage などの追加の入力バインディングから読み取るには、context.extraInputs.get() を使用します。
  • context.extraOutputs.set()を使ってキューなどの追加の出力バインディングに書き込みます。
  • 各関数は正確に1つのトリガーを持ちますが、複数の追加入力と出力を持つこともあります。
  • グローバル変数にデータをキャッシュして呼び出時に再利用することはできますが、この状態に永続性を期待しないでください。 ランタイムはいつでもワーカーを再利用できます。

Node.js v3プログラミングモデルでは、各関数を function.json 設定ファイルと対応するJavaScriptやTypeScriptコードを使って定義します。 関数を特定のファイル構造で別々のフォルダに整理します。 すべての関数には実行を開始する単一の トリガー があり、また入力データの読み取りや出力データの書き込みを行う他のサービスへの宣言的接続である バインディングを持つこともできます。 詳細については 、「トリガーとバインディング」をご覧ください。

v3モデルでは、あなたは:

  • function.jsonファイルでトリガーとバインディングを定義します。 入力には direction: "in" 、出力には direction: "out" を使いましょう。
  • トリガー入力をハンドラーに2つ目の引数としてアクセスするか、 context.bindingsから読み取ってください。
  • 出力は context.bindings に値を割り当てて設定します(例: context.bindings.outputQueue)。 HTTPの場合は context.resを使いましょう。
  • TypeScriptプロジェクトでは、コンパイルされたJavaScriptファイルを指し示すscriptFilefunction.jsonプロパティが必要です。
  • 各関数は正確に1つのトリガーを持ちますが、複数の入力および出力のバインディングを持つことができます。
  • グローバル変数にデータをキャッシュして呼び出時に再利用することはできますが、この状態に永続性を期待しないでください。 ランタイムはいつでもワーカーを再利用できます。

Examples

HTTP 要求に応答する単純な関数を次に示します。

const { app } = require('@azure/functions');

app.http('httpTrigger', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        const name = request.query.get('name') || 'World';
        context.log('HTTP trigger function processed a request.');

        return { body: `Hello, ${name}!` };
    }
});

以下の非HTTP例ではタイマートリガーが使われています:

const { app } = require('@azure/functions');

app.timer('cleanupTimer', {
  schedule: '0 */5 * * * *',
  handler: async (myTimer, context) => {
    context.log('Timer trigger function ran at', new Date().toISOString());
  }
});

以下の例は、キュー出力バインディングを持つHTTPトリガーを示しています。

const { app, output } = require('@azure/functions');

const queueOutput = output.storageQueue({
  queueName: 'work-items',
  connection: 'AzureWebJobsStorage'
});

app.http('submitWorkItem', {
  methods: ['POST'],
  extraOutputs: [queueOutput],
  handler: async (request, context) => {
    const body = await request.json();
    context.extraOutputs.set(queueOutput, JSON.stringify(body));
    return { status: 202, jsonBody: { accepted: true } };
  }
});

HTTP 要求に応答する単純な関数を次に示します。

{
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": ["get", "post"]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }
  ]
}
module.exports = async function (context, req) {
    const name = (req.query.name || (req.body && req.body.name)) || 'World';
    context.log('HTTP trigger function processed a request.');

    context.res = {
        body: `Hello, ${name}!`
    };
};

以下の非HTTP例ではタイマートリガーが使われています:

{
  "bindings": [
    {
      "name": "myTimer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "0 */5 * * * *"
    }
  ]
}
module.exports = async function (context, myTimer) {
    context.log('Timer trigger function ran at', new Date().toISOString());
};

以下の例は、キュー出力バインディングを持つHTTPトリガーを示しています。

{
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": ["post"]
    },
    {
      "type": "queue",
      "direction": "out",
      "name": "workItems",
      "queueName": "work-items",
      "connection": "AzureWebJobsStorage"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }
  ]
}
module.exports = async function (context, req) {
    const payload = req.body || {};
    context.bindings.workItems = JSON.stringify(payload);
    context.res = {
        status: 202,
        body: { accepted: true }
    };
};

関数アプリのビルド

このセクションでは、ノード関数アプリの作成と構造化に必要な重要な要素、 @azure/functions ライブラリプロジェクト構造パッケージ管理を扱います。

@azure/functions ライブラリ

@azure/functions TypeScript/JavaScript ライブラリは、Azure Functionsランタイムとやり取りするためのコア型と関数を提供します。 使用可能なすべての型とメソッドを確認するには、 @azure/functions API にアクセスしてください。

関数コードでは、 @azure/functions を使用して次のことができます。

  • 関数をレジスタし、トリガーを定義します(v4モデル)。
  • 強型トリガー入力データ(例: HttpRequestTimer)にアクセスできます。
  • HttpResponseInitのような型付けされた出力値を作成します。
  • ランタイムで提供されるコンテキストデータやバインディングデータとやり取りします。

アプリで @azure/functions を使っているなら、プロジェクト依存関係に含めてください:

{
  "dependencies": {
    "@azure/functions": "^4.0.0"
  }
}

@azure/functionsライブラリは Node.js Azure Functions のプログラミング面を定義しますが、汎用SDKではありません。 Azure Functions ランタイム内で関数を作成して実行する場合に特に使用します。

TypeScript の構成

最高のTypeScript開発体験を得るために、 tsconfig.json に適切な設定が含まれていることを確認してください:

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "outDir": "dist",
    "rootDir": ".",
    "sourceMap": true,
    "strict": false,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

フォルダー構造

JavaScriptプロジェクトには、以下の例に示されたフォルダ構造が必要です:

<project_root>/
 | - .vscode/
 | - node_modules/
 | - myFirstFunction/
 | | - index.js
 | | - function.json
 | - mySecondFunction/
 | | - index.js
 | | - function.json
 | - .funcignore
 | - host.json
 | - local.settings.json
 | - package.json

メイン プロジェクト フォルダー <project_root> には、次のファイルを含めることができます。

  • .vscode/: (省略可能) 格納されているVisual Studio Code構成が含まれます。 詳細については、Visual Studio Code設定を参照してください。
  • myFirstFunction/function.json: 関数のトリガー、入力、出力の構成が含まれています。 ディレクトリの名前によって、関数の名前が決まります。
  • myFirstFunction/index.js: 関数コードを保存します。 この既定のファイル パスを変更するには、「scriptFile の使用」を参照してください。
  • .funcignore: (省略可能) Azureに公開すべきではないファイルを宣言します。 通常、このファイルには. vscode/ が含まれており、エディターの設定を無視する、test / テストケースを無視する、ローカルアプリ設定の公開を防ぐ local.settings.json が含まれています。
  • host.json: 関数アプリ インスタンス内にあるすべての関数に影響する構成オプションが含まれます。 このファイルはAzureに公開されます。 ローカルで実行する場合は、すべてのオプションがサポートされるわけではありません。 詳細については、host.json に関するページを参照してください。
  • local.settings.json: ローカルで実行するとき、アプリ設定と接続文字列を格納するために使用されます。 このファイルはAzureに発行されません。 詳細については、「local.settings.file」に関するページを参照してください。
  • package.json: パッケージ依存関係のリスト、メインエントリポイント、スクリプトなどの設定オプションが含まれています。

JavaScriptプロジェクトは以下の例で推奨されるフォルダ構造に従っています:

<project_root>/
 | - .vscode/
 | - node_modules/
 | - src/
 | | - functions/
 | | | - myFirstFunction.js
 | | | - mySecondFunction.js
 | - test/
 | | - functions/
 | | | - myFirstFunction.test.js
 | | | - mySecondFunction.test.js
 | - .funcignore
 | - host.json
 | - local.settings.json
 | - package.json

メイン プロジェクト フォルダー <project_root> には、次のファイルを含めることができます。

  • .vscode/: (省略可能) 格納されているVisual Studio Code構成が含まれます。 詳細については、Visual Studio Code設定を参照してください。
  • src/functions/: すべての関数とそれに関連するトリガーとバインドの既定の場所です。
  • test/: (省略可能) 関数アプリのテスト ケースが含まれます。
  • .funcignore: (省略可能) Azureに公開すべきではないファイルを宣言します。 通常、このファイルには. vscode/ が含まれており、エディターの設定を無視する、test / テストケースを無視する、ローカルアプリ設定の公開を防ぐ local.settings.json が含まれています。
  • host.json: 関数アプリ インスタンス内にあるすべての関数に影響する構成オプションが含まれます。 このファイルはAzureに公開されます。 ローカルで実行する場合は、すべてのオプションがサポートされるわけではありません。 詳細については、host.json に関するページを参照してください。
  • local.settings.json: ローカルで実行するとき、アプリ設定と接続文字列を格納するために使用されます。 このファイルはAzureに発行されません。 詳細については、「local.settings.file」に関するページを参照してください。
  • package.json: パッケージ依存関係のリスト、メインエントリポイント、スクリプトなどの設定オプションが含まれています。

パッケージ管理

効果的なパッケージ管理は Node.js Azure Functions プロジェクトにとって非常に重要です。 このセクションでは、依存関係管理、パッケージ設定、関数アプリの依存関係を維持するためのベストプラクティスを扱います。

依存関係の管理

すべての Node.js Azure Functions プロジェクトはパッケージ管理にnpmを使用しています。 package.jsonファイルは、関数の構築と実行に必要なプロジェクトの構成、依存関係、スクリプトを定義しています。

本質的な package.json 構造:

{
  "name": "my-functions-app",
  "version": "1.0.0",
  "description": "Azure Functions Node.js app",
  "main": "src/index.js",
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "prestart": "npm run build",
    "start": "func start",
    "test": "jest"
  },
  "dependencies": {
    "@azure/functions": "^4.0.0"
  },
  "devDependencies": {
    "@azure/functions-core-tools": "^4.0.4670",
    "@types/node": "^18.0.0",
    "typescript": "^4.0.0",
    "jest": "^29.0.0"
  }
}

ランタイム依存関係と開発依存関係

依存関係を適切に分けましょう:

ランタイム依存関係(dependencies):

  • @azure/functions: Azure Functionsのコアライブラリ
  • ビジネスロジックライブラリ(lodash、axios、および類似パッケージ)
  • データベースドライバ(mongodb、mssql、および類似パッケージ)
  • Azure SDKパッケージ(@azure/storage-blob、@azure/cosmos、および類似パッケージ)

開発依存関係(devDependencies):

  • TypeScriptコンパイラと型定義
  • テストフレームワーク(Jest、Mocha)
  • ビルドツールとリンター
  • Azure Functions Core Tools (ローカル開発用)

TypeScript専用パッケージ

TypeScriptプロジェクトでは、以下の重要な開発依存関係を含めてください:

{
  "devDependencies": {
    "@types/node": "^18.0.0",
    "typescript": "^4.0.0",
    "@typescript-eslint/eslint-plugin": "^5.0.0",
    "@typescript-eslint/parser": "^5.0.0"
  }
}

セキュリティとアップデート

セキュリティの脆弱性に対処するために依存関係を定期的に更新しましょう:

# Check for outdated packages
npm outdated

# Update packages
npm update

# Audit for security issues
npm audit
npm audit fix

実行とデバッグ

このセクションでは、ローカル開発、デバッグ技術、Node.js Azure Functions のテスト戦略について扱います。

ローカル開発のセットアップ

前提条件:

セットアップ手順:

  1. 依存関係をインストールします。

    npm install
    
  2. TypeScriptプロジェクトを構築:

    npm run build
    
  3. ローカルランタイム開始:

    npm start
    # or directly:
    func start
    

環境構成

ローカル開発環境を local.settings.json以下で設定します:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "NODE_ENV": "development",
    "CUSTOM_ENV_VARIABLE": "local-value"
  },
  "Host": {
    "LocalHttpPort": 7071,
    "CORS": "*",
    "CORSCredentials": false
  }
}

デバッグ

Visual Studio Codeのデバッグ:

.vscode/launch.jsonを作成します。

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Attach to Node Functions",
      "type": "node",
      "request": "attach",
      "port": 9229,
      "preLaunchTask": "func: host start"
    }
  ]
}

.vscode/tasks.jsonを作成します。

{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "func",
      "label": "func: host start",
      "command": "host start",
      "problemMatcher": "$func-node-watch",
      "isBackground": true,
      "options": {
        "cwd": "${workspaceFolder}"
      }
    }
  ]
}

コマンドラインデバッグ:

# Start with debugging enabled
func start --p <port>

# For TypeScript, ensure you build first
npm run build
func start --p 9229

デプロイメント

このセクションでは、展開戦略、CI/CD統合、Node.js Azure Functions の本番環境のベストプラクティスを扱います。

配置方法

1. Visual Studio Codeのデプロイ:

  • Azure Functions 拡張をインストールしてください。
  • Azureパネルで関数アプリを右クリックします。
  • [関数アプリにデプロイ] を選択します。

2. Azure Functions Core Tools:

# Deploy to Azure
func azure functionapp publish <FunctionAppName>

# Deploy with custom settings
func azure functionapp publish <FunctionAppName> --build local --publish-local-settings

3. Azure CLI deployment:

# Deploy from local folder
az functionapp deployment source config-zip \
  --resource-group <ResourceGroupName> \
  --name <FunctionAppName> \
  --src <PathToZipFile>

運用構成

Azureでのアプリケーション設定:

本番環境変数の設定:

  • WEBSITE_NODE_DEFAULT_VERSION: ~18 または ~20 に設定します。
  • FUNCTIONS_WORKER_RUNTIME: nodeに設定します。
  • 接続文字列とAPIキーを安全なアプリ設定として使います。
  • NODE_ENV: productionに設定します。

トリガーとバインド

Azure Functionsでは、triggers を使用して関数の実行を開始し、bindings を使用して、コードをストレージ、キュー、データベースなどの他のサービスに接続します。 Node.js プログラミングモデルでは、モデルバージョンによってバインディングの宣言方法が異なります。

2 つの主な種類のバインディングが存在します。

  • トリガー (関数を開始する入力)
  • 入力と出力 (追加のデータ ソースまたは変換先)

使用可能なトリガーとバインドの詳細については、「 Azure Functions のトリガーとバインド」を参照してください。

例: BLOB 入力を使用したタイマー トリガー

この関数は10分ごとにトリガーされ、追加の入力を使ってBlobから読み込み、ブロブの内容を記録します。

const { app, input } = require('@azure/functions');

let CACHED_BLOB_DATA = null;

const blobInput = input.storageBlob({
    connection: 'BLOB_CONNECTION_SETTING',
    path: 'mycontainer/myblob.txt'
});

app.timer('TimerTriggerWithBlob', {
    schedule: '0 */10 * * * *',
    extraInputs: [blobInput],
    handler: async (myTimer, context) => {
        if (CACHED_BLOB_DATA === null) {
            // Read blob content and cache it
            CACHED_BLOB_DATA = context.extraInputs.get(blobInput);
            context.log(`Blob content cached: ${CACHED_BLOB_DATA?.substring(0, 100)}...`);
        }

        context.log(`Timer function executed at: ${new Date().toISOString()}`);
        context.log(`Using cached data of length: ${CACHED_BLOB_DATA?.length || 0}`);
    }
});

この関数は10分ごとにトリガーされ、バインディング設定を使ってBlobから読み込み、ブロブの内容を記録します。

{
  "scriptFile": "index.js",
  "bindings": [
    {
      "name": "myTimer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "0 */10 * * * *"
    },
    {
      "name": "blobInput",
      "type": "blob",
      "direction": "in",
      "path": "mycontainer/myblob.txt",
      "connection": "AzureWebJobsStorage"
    }
  ]
}
let CACHED_BLOB_DATA = null;

module.exports = async function (context, myTimer) {
    if (CACHED_BLOB_DATA === null) {
        // Read blob content and cache it
        CACHED_BLOB_DATA = context.bindings.blobInput;
        context.log(`Blob content cached: ${CACHED_BLOB_DATA?.substring(0, 100)}...`);
    }

    context.log(`Timer function executed at: ${new Date().toISOString()}`);
    context.log(`Using cached data of length: ${CACHED_BLOB_DATA?.length || 0}`);
};

例:キュー出力を伴うHTTPトリガー

この関数はHTTPリクエストでトリガーされ、メッセージをストレージキューに書き込み、HTTP応答を返します。

const { app, output } = require('@azure/functions');

const queueOutput = output.storageQueue({
    connection: 'AzureWebJobsStorage',
    queueName: 'myqueue'
});

app.http('httpTriggerWithQueue', {
    methods: ['GET', 'POST'],
    extraOutputs: [queueOutput],
    handler: async (request, context) => {
        const name = request.query.get('name') || 'World';
        const message = {
            id: context.invocationId,
            name: name,
            timestamp: new Date().toISOString()
        };

        // Write to queue output
        context.extraOutputs.set(queueOutput, JSON.stringify(message));
        context.log(`Message sent to queue: ${JSON.stringify(message)}`);

        return {
            body: `Hello, ${name}! Message queued successfully.`
        };
    }
});

この関数はHTTPリクエストでトリガーされ、メッセージをストレージキューに書き込み、HTTP応答を返します。

{
  "scriptFile": "index.js",
  "bindings": [
    {
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": ["get", "post"]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    },
    {
      "type": "queue",
      "direction": "out",
      "name": "outputQueue",
      "queueName": "myqueue",
      "connection": "AzureWebJobsStorage"
    }
  ]
}
module.exports = async function (context, req) {
    const name = (req.query.name || (req.body && req.body.name)) || 'World';
    const message = {
        id: context.invocationId,
        name: name,
        timestamp: new Date().toISOString()
    };

    // Write to queue output
    context.bindings.outputQueue = JSON.stringify(message);
    context.log(`Message sent to queue: ${JSON.stringify(message)}`);

    return {
        status: 200,
        body: `Hello, ${name}! Message queued successfully.`
    };
};

app モジュールによってエクスポートされる triggerinputoutput@azure/functions のオブジェクトは、ほとんどの型に対して型固有のメソッドが用意されています。 サポートされていないすべての型については、手動で構成を指定できる generic メソッドが用意されています。 また、generic メソッドは、型固有のメソッドに指定されている既定の設定を変更する場合にも使用できます。

次の例は、型固有のメソッドではなく、ジェネリック メソッドを使った簡単な HTTP トリガー関数です。

const { app, output, trigger } = require("@azure/functions");

app.generic("helloWorld1", {
  trigger: trigger.generic({
    type: "httpTrigger",
    methods: ["GET", "POST"],
  }),
  return: output.generic({
    type: "http",
  }),
  handler: async (request, context) => {
    context.log(`Http function processed request for url "${request.url}"`);

    return { body: `Hello, world!` };
  },
});

::: ゾーン終了

呼び出しコンテキスト

関数が呼び出されるたびに、invocation context オブジェクトを受け取ります。 このオブジェクトを使って入力の読み取り、出力の設定、ログへの書き込み、さまざまなメタデータへのアクセスを行います。 v3モデルでは、必ずコンテキストオブジェクトをハンドラーに最初の引数として渡します。

contextオブジェクトには以下の性質が含まれます:

プロパティ 説明
invocationId 現在の関数呼び出しの ID。
executionContext 実行コンテキストに関するページを参照してください。
bindings バインディングに関するページを参照してください。
bindingData この呼び出しのトリガー入力に関するメタデータで、値自体は除外されます。 たとえば、イベント ハブ トリガーには enqueuedTimeUtc プロパティがあります。
traceContext 分散トレース用のコンテキスト。 詳細については、Trace Contextを参照してください。
bindingDefinitions function.json で定義されている入力と出力の構成。
req HTTP 要求」を参照してください。
res HTTP 応答」を参照してください。

context.executionContext

context.executionContext オブジェクトには、次のプロパティがあります。

プロパティ 説明
invocationId 現在の関数呼び出しの ID。
functionName 呼び出している関数の名前です。 function.json ファイルを含むフォルダーの名前によって、関数の名前が決まります。
functionDirectory function.json ファイルを含むフォルダー。
retryContext 再試行コンテキスト」を参照してください。

context.executionContext.retryContext

context.executionContext.retryContext オブジェクトには、次のプロパティがあります。

プロパティ 説明
retryCount 現在の再試行を表す数値。
maxRetryCount 実行が再試行される回数の最大数。 値 -1 は、無制限に再試行することを意味します。
exception 再試行の原因となった例外。

context.bindings

context.bindingsオブジェクトを使って入力を読み取ったり、出力を設定したりします。 以下の例は、context.bindingsを使用してストレージ BLOB 入力ストレージ BLOB 出力にコピーするストレージ キュー トリガーです。 キュー メッセージのコンテンツは、{queueTrigger}を利用して、コピーするファイル名として を置き換えます。

{
    "name": "myQueueItem",
    "type": "queueTrigger",
    "direction": "in",
    "connection": "storage_APPSETTING",
    "queueName": "helloworldqueue"
},
{
    "name": "myInput",
    "type": "blob",
    "direction": "in",
    "connection": "storage_APPSETTING",
    "path": "helloworld/{queueTrigger}"
},
{
    "name": "myOutput",
    "type": "blob",
    "direction": "out",
    "connection": "storage_APPSETTING",
    "path": "helloworld/{queueTrigger}-copy"
}
module.exports = async function (context, myQueueItem) {
  const blobValue = context.bindings.myInput;
  context.bindings.myOutput = blobValue;
};

context.done

context.done メソッドは非推奨です。 Azure Functions が非同期関数をサポートする前は、context.done() を呼び出すことで関数が完了したことを知らせていました。

module.exports = function (context, request) {
  context.log("this pattern is now deprecated");
  context.done();
};

context.done() 呼び出しを削除します。 関数を async として宣言し、何も await しなくても Promise を返すようにしましょう。 関数が終了すると (つまり、返された Promise が解決されると)、v3 モデルは関数が完了したことを認識します。

module.exports = async function (context, request) {
  context.log("you don't need context.done or an awaited call");
};

関数が呼び出されるたびに、呼び出しcontextオブジェクトを受け取ります。 このオブジェクトには、呼び出しやログの方法に関する情報が含まれています。 v4モデルでは、通常 context オブジェクトをハンドラーに2つ目の引数として渡します。

InvocationContext クラスには、次のプロパティが含まれています。

プロパティ 説明
invocationId 現在の関数呼び出しの ID。
functionName 関数の名前です。
extraInputs 追加の入力の値を取得するために使われます。 詳細については、「追加の入力と出力」を参照してください。
extraOutputs 追加の出力の値を取得するために使われます。 詳細については、「追加の入力と出力」を参照してください。
retryContext 再試行コンテキスト」を参照してください。
traceContext 分散トレース用のコンテキスト。 詳細については、Trace Contextを参照してください。
triggerMetadata 値そのものを含まない、この呼び出しのトリガー入力に関するメタデータ。 たとえば、イベント ハブ トリガーには enqueuedTimeUtc プロパティがあります。
options 関数登録時に使うオプションは、検証されデフォルトが明示的に指定された後に行われます。

再試行コンテキスト

retryContext オブジェクトには、次のプロパティがあります。

プロパティ 説明
retryCount 現在の再試行を表す数値。
maxRetryCount 実行が再試行される回数の最大数。 値 -1 は、無制限に再試行することを意味します。
exception 再試行の原因となった例外。

詳細については、retry-policiesを参照してください。

ログ記録

Azure Functionsでは、context.log()を使ってログを書きます。 Azure Functions Azure アプリケーション Insights と統合して、関数アプリのログをより適切にキャプチャします。 Application Insights は、Azure Monitorの一部であり、アプリケーション ログとトレース出力の両方を収集、ビジュアルレンダリング、分析するための機能を提供します。 詳細については、Azure Functionsの監視を参照してください。

代替 Node.js console.log 方法を使うと、アプリレベルのログは追跡されますが、特定の機能とは関連していません。 ログにはcontextではなくconsoleを使い、すべてのログを特定の関数に関連付けましょう。

次の例では、既定の「情報」レベルで呼び出し ID を含む、ログを書き込んでいます。

context.log(`Something has happened. Invocation ID: "${context.invocationId}"`);

ログ レベル

デフォルトの context.log メソッドに加えて、以下の方法で特定のレベルでログを書き込むことができます:

Method 説明
context.log.error() ログにエラーレベルのイベントを書き込みます。
context.log.warn() 警告レベルのイベントをログに書き込みます。
context.log.info() 情報レベル イベントをログに書き込みます。
context.log.verbose() トレースレベル イベントをログに書き込みます。
Method 説明
context.trace() トレースレベル イベントをログに書き込みます。
context.debug() デバッグレベル イベントをログに書き込みます。
context.info() 情報レベル イベントをログに書き込みます。
context.warn() 警告レベルのイベントをログに書き込みます。
context.error() ログにエラーレベルのイベントを書き込みます。

ログ レベルの構成

Functionsでは、ログの追跡と閲覧の閾値を定義できます。 しきい値を設定するには、logging.logLevel ファイルの host.json プロパティを使用します。 このプロパティにより、すべての関数のデフォルトレベルや各関数の閾値を定義できます。 詳細については、「Azure Functionsを参照してください。

カスタム データを追跡する

既定では、Azure Functionsは出力をトレースとして Application Insights に書き込みます。 より細かい制御を目的として、 Application Insights Node.js SDK を使ってカスタムログ、メトリクス、依存関係をApplication Insightsインスタンスに送信してください。

Application Insights Node.js SDK のメソッドは、時間の経過と同時に変更される可能性があります。 ここで示す例とは、構文に小さな違いがある可能性があります。 最新の API の使用例については、 Application Insights Node.js SDK のドキュメントを参照してください

Node.js v4プログラミングモデルでの分散トレースでは、Application Insights SDKの代わりに @azure/functions-opentelemetry-instrumentation パッケージを使用してください。 このパッケージは、Azure Functions用の OpenTelemetry ベースの自動インストルメンテーションを提供します。 詳細については、OpenTelemetry Azure Functions Instrumentation for Node.js GitHub リポジトリを参照してください。

const appInsights = require("applicationinsights");
appInsights.setup();
const client = appInsights.defaultClient;

module.exports = async function (context, request) {
  // Use this with 'tagOverrides' to correlate custom logs to the parent function invocation.
  var operationIdOverride = {
    "ai.operation.id": context.traceContext.traceparent,
  };

  client.trackEvent({
    name: "my custom event",
    tagOverrides: operationIdOverride,
    properties: { customProperty2: "custom property value" },
  });
  client.trackException({
    exception: new Error("handled exceptions can be logged with this method"),
    tagOverrides: operationIdOverride,
  });
  client.trackMetric({
    name: "custom metric",
    value: 3,
    tagOverrides: operationIdOverride,
  });
  client.trackTrace({
    message: "trace message",
    tagOverrides: operationIdOverride,
  });
  client.trackDependency({
    target: "http://dbname",
    name: "select customers proc",
    data: "SELECT * FROM Customers",
    duration: 231,
    resultCode: 0,
    success: true,
    dependencyTypeName: "ZSQL",
    tagOverrides: operationIdOverride,
  });
  client.trackRequest({
    name: "GET /customers",
    url: "http://myserver/customers",
    duration: 309,
    resultCode: 200,
    success: true,
    tagOverrides: operationIdOverride,
  });
};

tagOverrides パラメーターにより、関数の呼び出し ID に operation_Id を設定します。 この設定により、特定の関数呼び出しに対して自動生成およびカスタムログをすべて相関させることができます。

HTTP トリガー

HTTP および webhook トリガーでは、要求オブジェクトと応答オブジェクトを使用して HTTP メッセージを表します。

HTTP および webhook トリガーでは、HttpRequest オブジェクトと HttpResponse オブジェクトを使用して HTTP メッセージを表します。 これらのクラスは、Node.js の パッケージを使って、undiciのサブセットを表しています。

HTTP 要求

リクエストにアクセスする方法は以下の通りです:

  • 関数の 2 番目の引数として:

    module.exports = async function (context, request) {
        context.log(`Http function processed request for url "${request.url}"`);
    

  • context.req プロパティから:

    module.exports = async function (context, request) {
        context.log(`Http function processed request for url "${context.req.url}"`);
    

  • 名前付き入力バインディングから: このオプションは非HTTPバインディングと同じように動作します。 function.json のバインド名は、context.bindings のキー、または次の例の「request1」と一致している必要があります。

    {
      "name": "request1",
      "type": "httpTrigger",
      "direction": "in",
      "authLevel": "anonymous",
      "methods": ["get", "post"]
    }
    
    module.exports = async function (context, request) {
        context.log(`Http function processed request for url "${context.bindings.request1.url}"`);
    

HttpRequest オブジェクトには、次のプロパティがあります。

プロパティ タイプ 説明
method string この関数を呼び出すために使われる HTTP 要求メソッド。
url string 要求 URL。
headers Record<string, string> HTTP 要求ヘッダー。 このオブジェクトでは、大文字と小文字が区別されます。 代わりに request.getHeader('header-name') を使用してください。これは大文字と小文字を区別しません。
query Record<string, string> URL の文字列パラメーター キーと値のクエリを実行します。
params Record<string, string> ルート パラメーター キーと値。
user HttpRequestUser \| null ログインしたユーザーを表すオブジェクト。Functions の認証、SWA 認証、またはそのようなユーザーがログインしていない場合は null。
body Buffer \| string \| any メディアの種類が "application/octet-stream" または "multipart/*" の場合、body はバッファーです。 値が JSON 解析可能な文字列の場合、body は解析されたオブジェクトです。 それ以外の場合、body は文字列です。
rawBody string 文字列としての本文。 名前にもかかわらず、このプロパティは Buffer を返しません。
bufferBody Buffer バッファーとしての本文。

HTTPトリガー関数のハンドラーの最初の引数としてリクエストにアクセスできます。

async (request, context) => {
    context.log(`Http function processed request for url "${request.url}"`);

HttpRequest オブジェクトには、次のプロパティがあります。

プロパティ タイプ 説明
method string この関数を呼び出すために使われる HTTP 要求メソッド。
url string 要求 URL。
headers Headers HTTP 要求ヘッダー。
query URLSearchParams URL の文字列パラメーター キーと値のクエリを実行します。
params Record<string, string> ルート パラメーター キーと値。
user HttpRequestUser \| null ログインしたユーザーを表すオブジェクト。Functions の認証、SWA 認証、またはそのようなユーザーがログインしていない場合は null。
body ReadableStream \| null 読み取り可能なストリームとしての本文。
bodyUsed boolean 本文が既読かどうかを示すブール値。

リクエストやレスポンスの本文にアクセスするには、以下の方法を使用します。

Method 戻り値の型
arrayBuffer() Promise<ArrayBuffer>
blob() Promise<Blob>
formData() Promise<FormData>
json() Promise<unknown>
text() Promise<string>

体の機能検査は一度しか実行できません。 その後の呼び出しは空文字列またはArrayBufferで解決されます。

HTTP 応答

応答は複数の方法で設定できます。 たとえば、次のように使用できます。

  • context.res プロパティを設定する:

    module.exports = async function (context, request) {
        context.res = { body: `Hello, world!` };
    

  • 応答を返す: 関数が非同期で、$return でバインド名を function.json に設定している場合、context に設定するのではなく、応答を直接返すことができます。

    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
    
    module.exports = async function (context, request) {
        return { body: `Hello, world!` };
    

  • 名前付きの出力バインディングを設定します: このオプションは非HTTPバインディングと同じように動作します。 function.json のバインド名は、context.bindings のキー、または次の例の「response1」と一致している必要があります。

    {
      "type": "http",
      "direction": "out",
      "name": "response1"
    }
    
    module.exports = async function (context, request) {
        context.bindings.response1 = { body: `Hello, world!` };
    

  • context.res.send() を呼び出す: このオプションは非推奨です。 暗黙のうちに context.done() を呼び出し、非同期関数では使えません。

    module.exports = function (context, request) {
        context.res.send(`Hello, world!`);
    

応答を設定するときに新しいオブジェクトを作成する場合、そのオブジェクトはインターフェイスと HttpResponseSimple 一致している必要があります。このインターフェイスには、次のプロパティがあります。

プロパティ タイプ 説明
headers Record<string, string> (任意) HTTP 応答ヘッダー。
cookies Cookie[] (任意) HTTP 応答の Cookie。
body any (任意) HTTP 応答の本文。
statusCode number (任意) HTTP 応答状態コード。 設定しない場合の既定値は 200 です。
status number (任意) statusCode と同じです。 statusCode を設定した場合、このプロパティは無視されます。

context.res オブジェクトは、上書きせずに変更することもできます。 既定の context.res オブジェクトでは、HttpResponseFull インターフェイスが使用されます。このインターフェイスでは、HttpResponseSimple プロパティに加えて次のメソッドがサポートされています。

Method 説明
status() 状態を設定します。
setHeader() ヘッダー フィールドを設定します。 注:res.set()res.header()もサポートされていて同じことをしています。
getHeader() ヘッダーフィールドが割り当てられます。 注:res.get() こちらも対応しており、同じことができます。
removeHeader() ヘッダーを削除します。
type() "content-type" ヘッダーを設定します。
send() このメソッドは非推奨とされます。 本文を設定し、context.done() を呼び出して、同期関数が終了したことを示します。 注:res.end() こちらも対応しており、同じことができます。
sendStatus() このメソッドは非推奨とされます。 状態コードを設定し、context.done() を呼び出して、同期関数が完了したことを示します。
json() このメソッドは非推奨とされます。 "content-type" を "application/json" に設定し、本文を設定し、context.done() を呼び出して、同期関数が完了したことを示します。

応答は複数の方法で設定できます。 たとえば、次のように使用できます。

  • タイプ HttpResponseInitのシンプルなインターフェース: このオプションは応答を返す最も簡潔な方法です。

    return { body: `Hello, world!` };
    

HttpResponseInit インターフェイスには次のプロパティがあります。

プロパティ タイプ 説明
body BodyInit (任意) ArrayBufferAsyncIterable<Uint8Array>BlobFormDataIterable<Uint8Array>NodeJS.ArrayBufferViewURLSearchParamsnullstring のいずれかの HTTP 応答本文。
jsonBody any (任意) JSON でシリアル化可能な HTTP 応答の本文。 設定した場合、このプロパティが優先され、HttpResponseInit.body プロパティは無視されます。
status number (任意) HTTP 応答状態コード。 設定しない場合の既定値は 200 です。
headers HeadersInit (任意) HTTP 応答ヘッダー。
cookies Cookie[] (任意) HTTP 応答の Cookie。
  • HttpResponse のクラスのクラスとして: このオプションの場合、ヘッダーのような応答のさまざまな部分を読み取り、変更するヘルパー メソッドを利用できます。

    const response = new HttpResponse({ body: `Hello, world!` });
    response.headers.set("content-type", "application/json");
    return response;
    

HttpResponse クラスは、コンストラクターの引数として省略可能な HttpResponseInit を受け取ります。また、次のプロパティがあります。

プロパティ タイプ 説明
status number HTTP 応答状態コード。
headers Headers HTTP 応答ヘッダー。
cookies Cookie[] HTTP 応答の Cookie。
body ReadableStream | null 読み取り可能なストリームとしての本文。
bodyUsed boolean 本文が既読かどうかを示すブール値。

HTTP ストリーム

HTTP ストリームは、大規模なデータの処理、OpenAI 応答のストリーミング、動的コンテンツの配信、その他のコア HTTP シナリオのサポートを容易にする機能です。 これにより、Node.js 関数アプリの HTTP エンドポイントへの要求と HTTP エンドポイントからの応答をストリーミングできます。 アプリで、HTTP を経由してクライアントとサーバー間でリアルタイムの交換や対話を行う必要があるシナリオでは、HTTP ストリームを使用します。 また、HTTP ストリームを使用すると、HTTP を使用するときにアプリのパフォーマンスと信頼性を最大限に高めることができます。

重要

HTTP ストリームは、v3 モデルではサポートされていません。 HTTP ストリーム機能を使用するには、v4 モデルにアップグレードしてください。 プログラミング モデル v4 の既存の HttpRequest 型と HttpResponse 型では、ストリームとして処理するなど、メッセージ本文を処理するさまざまな方法が既にサポートされています。

前提条件

ストリームを有効にする

Azureおよびローカル プロジェクトで関数アプリで HTTP ストリームを有効にするには、次の手順を使用します。

  1. 大量のデータをストリーミングする場合は、Azureの FUNCTIONS_REQUEST_BODY_SIZE_LIMIT 設定を変更します。 デフォルトの最大ボディサイズは 104857600で、リクエストのサイズは約100MBに制限されます。

  2. ローカル開発の場合は、さらに、FUNCTIONS_REQUEST_BODY_SIZE_LIMITlocal.settings.json ファイルに追加します。

  3. アプリのメイン フィールドに含まれる任意のファイル内のアプリに次のコードを追加します。

    const { app } = require("@azure/functions");
    
    app.setup({ enableHttpStream: true });
    

ストリームの例

以下の例は、HTTP POSTリクエストを通じてデータを受け取るHTTPトリガー関数を示しています。 関数はこのデータを指定された出力ファイルにストリーミングします:

const { app } = require('@azure/functions');
const { createWriteStream } = require('fs');
const { Writable } = require('stream');

app.http('httpTriggerStreamRequest', {
    methods: ['POST'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        const writeStream = createWriteStream('<output file path>');
        await request.body.pipeTo(Writable.toWeb(writeStream));

        return { body: 'Done!' };
    },
});

以下の例は、HTTPトリガー関数を示しており、ファイルの内容を受信するHTTP GETリクエストへの応答として配信します。

const { app } = require('@azure/functions');
const { createReadStream } = require('fs');

app.http('httpTriggerStreamResponse', {
    methods: ['GET'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        const body = createReadStream('<input file path>');

        return { body };
    },
});

ストリームを使ったすぐに使えるサンプルアプリとして、GitHubのこの例をチェックしてみてください。

ストリームに関する考慮事項

  • ストリームの活用を最大限に活用するために request.body 活用しましょう。 request.text()のような方法を使うことは可能です。これらは常に本体を文字列として返します。

フック

v3モデルはフックに対応していません。 フックを使用するには、v4 モデル にアップグレードします。

フックを使用して、Azure Functionsライフサイクルのさまざまなポイントでコードを実行します。 フックを登録する順序によって、実行される順番が決まります。 アプリのどのファイルからもフックを登録できます。 フックには「アプリ」レベルと「呼び出し」レベルの2つのスコープがあります。

呼び出しフック

呼び出しフックは関数の呼び出しごとに1回実行されます。 preInvocationフックは関数の実行前に動作し、postInvocationフックは関数の実行後に実行されます。 デフォルトでは、フックはすべてのトリガータイプで実行されますが、タイプごとにフィルターもできます。 次の例は、呼び出しフックを登録し、トリガーの種類でフィルター処理する方法を示しています。

const { app } = require('@azure/functions');

// Pre-invocation hook with trigger filtering
app.hook.preInvocation('httpPreInvocation', async (context) => {
  context.hookData.startTime = Date.now();
  context.invocationContext.log(`Pre-invocation hook executed for ${context.invocationContext.functionName}`);

  // Add custom headers or modify function handler if needed
  if (context.functionHandler.name === 'httpTrigger') {
    context.invocationContext.log('HTTP function detected, preparing request processing');
  }
}, {
  filter: ['httpTrigger']
});

// Post-invocation hook
app.hook.postInvocation('httpPostInvocation', async (context) => {
  const duration = Date.now() - context.hookData.startTime;
  context.invocationContext.log(`Function ${context.invocationContext.functionName} completed in ${duration}ms`);

  // Log results or errors
  if (context.error) {
    context.invocationContext.log.error(`Function failed: ${context.error.message}`);
  } else {
    context.invocationContext.log(`Function succeeded with result: ${JSON.stringify(context.result)}`);
  }
}, {
  filter: ['httpTrigger']
});

フック ハンドラーの最初の引数は、そのフックの種類に固有のコンテキスト オブジェクトです。

PreInvocationContext オブジェクトには、次のプロパティがあります。

プロパティ 説明
inputs 呼び出しに渡す引数。
functionHandler 呼び出しの関数ハンドラー。 この値を変更すると、関数自体に影響します。
invocationContext 関数に渡される呼び出しコンテキスト オブジェクト。
hookData 同じスコープ内のフック間でデータを格納および共有するための推奨される場所。 他のフックのデータと競合しないように、固有のプロパティ名を使いましょう。

PostInvocationContext オブジェクトには、次のプロパティがあります。

プロパティ 説明
inputs 呼び出しに渡す引数。
result 関数の結果。 この値に対する変更は、関数の全体的な結果に影響します。
error 関数によってスローされたエラー。エラーがない場合は null または undefined。 この値に対する変更は、関数の全体的な結果に影響します。
invocationContext 関数に渡される呼び出しコンテキスト オブジェクト。
hookData 同じスコープ内のフック間でデータを格納および共有するための推奨される場所。 他のフックのデータと競合しないように、固有のプロパティ名を使いましょう。

アプリ フック

ランタイムはアプリフックを1インスタンスごとに1回実行します。 起動時には appStart フックを実行し、終了時には appTerminate フックを実行します。 アプリ終了フックの実行時間は限られており、すべてのシナリオで実行されるわけではありません。

現在、Azure Functions ランタイムは呼び出しの外部でのコンテキスト ログ記録をサポートしていません。 Application Insights の npm パッケージを使用して、アプリ レベルのフック中にデータをログに記録します。

次の例では、アプリ フックを登録します。

const { app } = require('@azure/functions');
const appInsights = require('applicationinsights');

// Initialize Application Insights for app-level logging
appInsights.setup().start();
const client = appInsights.defaultClient;

// App start hook
app.hook.appStart('appStartup', async (context) => {
  context.hookData.appStartTime = Date.now();
  context.hookData.initializationData = {};

  // Initialize shared resources, database connections, etc.
  client.trackEvent({
    name: 'FunctionAppStarted',
    properties: {
      timestamp: new Date().toISOString(),
      nodeVersion: process.version
    }
  });

  // Set up global configurations
  process.env.APP_INITIALIZED = 'true';
});

// App terminate hook
app.hook.appTerminate('appShutdown', async (context) => {
  const uptime = Date.now() - context.hookData.appStartTime;

  // Cleanup resources, close connections, etc.
  client.trackEvent({
    name: 'FunctionAppTerminated',
    properties: {
      uptime: uptime,
      timestamp: new Date().toISOString()
    }
  });

  // Flush Application Insights data
  await new Promise((resolve) => client.flush({ callback: resolve }));
});

フック ハンドラーの最初の引数は、そのフックの種類に固有のコンテキスト オブジェクトです。

AppStartContextオブジェクトは以下の性質を持ちます:

プロパティ 説明
hookData 同じスコープ内のフック間でデータを格納および共有するための推奨される場所。 他のフックのデータと競合しないように、固有のプロパティ名を使いましょう。

AppTerminateContextオブジェクトは以下の性質を持ちます:

プロパティ 説明
hookData 同じスコープ内のフック間でデータを格納および共有するための推奨される場所。 他のフックのデータと競合しないように、固有のプロパティ名を使いましょう。

フックのベストプラクティス

Azure Functionsでフックを使用する際は、以下のベストプラクティスを考慮してください:

パフォーマンスに関する考慮事項

  • 関数のパフォーマンスに影響を及ぼさないため、フック実行時間を最小限に抑えましょう。
  • 可能な限り非同期操作を用いてブロッキングを防ぎましょう。
  • 大量のリクエストを処理する際は、フックのオーバーヘッドを考慮してください。

エラー処理

  • フックには必ず適切なエラー処理を含めてください。
  • 絶対に必要な場合を除き、フックの故障で機能障害を起こさないようにしましょう。
  • デバッグ用に、フックのエラーを適切にログに記録します。

データの共有

  • hookDataを使って、召喚前と事後のフック間で情報を共有しましょう。
  • 他のフックとの競合を避けるために、ユニークなプロパティ名を使いましょう。
  • 不要なフックデータをクリーンアップしてメモリリークを防ぎます。

フィルター処理

  • トリガータイプフィルタリングを使って、フックが関連する関数だけを実行するようにしましょう。
  • パフォーマンスを最適化するためにフィルターを具体的に設定しましょう。

スケーリングとコンカレンシー

既定では、Azure Functionsはアプリケーションの負荷を自動的に監視し、必要に応じて Node.js のホスト インスタンスを作成します。 Azure Functionsは、メッセージの年齢やQueueTriggerのキューサイズなど、インスタンスを追加するタイミングを決めるために、ユーザー設定不可の組み込みの閾値を使い、異なるトリガータイプを決定します。 詳細については、「従量課金プランと Premium プランのしくみ」をご覧ください。

ほとんどの Node.js アプリケーションでは、このスケーリング動作で十分です。 CPUにバインドされたアプリケーションの場合、複数の言語ワーカープロセスを使用して、パフォーマンスをさらに向上させることができます。 FUNCTIONS_WORKER_PROCESS_COUNT アプリケーション設定を使用して、ホストあたりのワーカー プロセスの数を既定の 1 から最大 10 まで増やすことができます。 Azure Functions、これらのワーカー間で同時関数呼び出しを均等に分散しようとします。 この動作により、CPU を集中的に使用する関数が、他の関数の実行をブロックする可能性が低くなります。 この設定は、需要に合わせてアプリケーションをスケールアウトするときに作成Azure Functions各ホストに適用されます。

警告

FUNCTIONS_WORKER_PROCESS_COUNT 設定を使用するときには注意が必要です。 同じインスタンスで複数のプロセスを実行すると、予期しない動作が発生し、関数の読み込み時間が長くなる可能性があります。 この設定を使うと、 パッケージファイルから実行 することでこれらのデメリットを相殺できます。

Node バージョン

ランタイムが使用している現在のバージョンを確認するには、任意の関数から process.version をログに記録します。 各プログラミング モデルでサポートされる Node.js バージョンの一覧については supported versions を参照してください。

Node のバージョンを設定する

Node.js バージョンをアップグレードする方法は、関数アプリを実行する OS によって異なります。

Windowsで動作するときは、WEBSITE_NODE_DEFAULT_VERSIONアプリケーション設定を使って Node.js バージョンを設定します。 この設定はAzure CLIを使用するか、Azureポータルで更新してください。

Node.js バージョンの詳細については、「使用可能なバージョン」を参照してください。

Node.js バージョンをアップグレードする前に、関数アプリが最新バージョンの Azure Functions ランタイムで実行されていることを確認します。 ランタイム バージョンをアップグレードする必要がある場合は、Azure Functions のバージョン 3.x からバージョン 4.x にアプリを移行する方法についてのドキュメントを参照してください。

Azure CLI az functionapp config appsettings set コマンドを実行して、Windowsで実行されている関数アプリの Node.js バージョンを更新します。

az functionapp config appsettings set  --settings WEBSITE_NODE_DEFAULT_VERSION=~22 \
 --name <FUNCTION_APP_NAME> --resource-group <RESOURCE_GROUP_NAME>

このコマンドは、 WEBSITE_NODE_DEFAULT_VERSION アプリケーション設定 をサポートされているLTSバージョン ~22に設定します。

変更を加えると、関数アプリが再起動します。 Functions の Node.js サポートの詳細については、「言語ランタイム サポート ポリシー」を参照してください。

環境変数

環境変数を使って、接続文字列、キー、エンドポイントなどの操作秘密を管理します。 また、環境設定、例えば変数のプロファイリングにも使うのが良いでしょう。 ローカル環境とクラウド環境の両方に環境変数を追加し、関数コードの process.env を通じてアクセスします。

次の例では、WEBSITE_SITE_NAME 環境変数をログに記録します。

module.exports = async function (context) {
  context.log(`WEBSITE_SITE_NAME: ${process.env["WEBSITE_SITE_NAME"]}`);
};
async function timerTrigger1(myTimer, context) {
  context.log(`WEBSITE_SITE_NAME: ${process.env["WEBSITE_SITE_NAME"]}`);
}

ローカル開発環境

ローカルで実行する場合は、関数プロジェクトに local.settings.json ファイルが含まれています。ここに Values オブジェクトの環境変数を格納します。

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "CUSTOM_ENV_VAR_1": "hello",
    "CUSTOM_ENV_VAR_2": "world"
  }
}

Azure クラウド環境

Azureで実行すると、関数アプリを使用すると、サービス接続文字列などの Application 設定を設定して使用でき、実行中にこれらの設定が環境変数として公開されます。

関数アプリの設定は、いくつかの方法で追加、更新、削除できます。

関数アプリの設定に変更を加えるためには、関数アプリを再起動する必要があります。

worker 環境変数

Node.js には固有のいくつかの関数環境変数があります:

languageWorkers__node__arguments

Node.js プロセスを始める際にカスタム引数を指定するためにこの設定を使いましょう。 多くの場合、ローカルでワーカーをデバッグモードで起動しますが、カスタム引数が必要な場合はAzureでも使えます。

警告

可能であれば、AzureでのlanguageWorkers__node__argumentsの使用は避けてください。冷たい始動時間に悪影響を及ぼす可能性があります。 予備ウォームされたワーカーを使う代わりに、ランタイムはカスタム引数を使って新しいワーカーを一から起動しなければなりません。

logginglogLevelWorker

この設定を使って、Node.js作業員専用ログのデフォルトログレベルを調整してください。 既定では、警告またはエラー ログのみが表示されますが、Node.js worker の問題を診断するのに役立つように information または debug に設定できます。 詳細については、「ログ レベルを構成する」を参照してください。

ECMAScript モジュール (プレビュー)

ECMAScriptモジュールは現在、Azure Functionsの Node.js 14以上でプレビュー機能として利用されています。

ECMAScript モジュール (ES モジュール) は、Node.js 用の新しい公式標準モジュール システムです。 これまで、この記事のコード サンプルは、CommonJS 構文を使用しています。 Node.js 14以上でAzure Functionsを動かす場合、ESモジュールの構文を使って関数を書くことができます。

関数で ES モジュールを使用するには、.mjs 拡張子を使用するようにファイル名を変更します。 次の index.mjs ファイルの例は、ES モジュール構文を使用して uuid ライブラリをインポートし、値を返す、HTTP によってトリガーされる関数です。

import { v4 as uuidv4 } from "uuid";

async function httpTrigger1(context, request) {
  context.res.body = uuidv4();
}

export default httpTrigger;
import { v4 as uuidv4 } from "uuid";

async function httpTrigger1(request, context) {
  return { body: uuidv4() };
}

app.http("httpTrigger1", {
  methods: ["GET", "POST"],
  handler: httpTrigger1,
});

関数のエントリ ポイントを構成する

function.jsonプロパティscriptFileentryPointを使って、エクスポートした関数の場所と名前を設定してください。 TypeScriptを使う場合は scriptFile プロパティが必要で、コンパイルされたJavaScriptを指すはずです。

scriptFile の使用

デフォルトでは、JavaScript関数は index.jsから動作します。 このファイルは対応する function.json ファイルと同じ親ディレクトリを共有しています。

フォルダの構造を整理するには scriptFile を使ってください。 以下の例はフォルダを設定する一つの方法を示しています:

<project_root>/
 | - node_modules/
 | - myFirstFunction/
 | | - function.json
 | - lib/
 | | - sayHello.js
 | - host.json
 | - package.json

function.jsonmyFirstFunctionファイルには、エクスポートした関数が実行されるファイルを示すscriptFileプロパティを含めるべきです。

{
  "scriptFile": "../lib/sayHello.js",
  "bindings": [
    ...
  ]
}

entryPoint の使用

v3モデルでは、関数を見つけて実行できるように module.exports を使って関数をエクスポートする必要があります。 デフォルトでは、トリガー時に実行される関数だけがそのファイルからのエクスポート手段です。 また、 run という名前のエクスポートや indexという名前のエクスポートも可能です。 次の例では、entryPointfunction.json をカスタム値 "logHello" に設定します。

{
  "entryPoint": "logHello",
  "bindings": [
    ...
  ]
}
async function logHello(context) {
  context.log("Hello, world!");
}

module.exports = { logHello };

推奨事項

このセクションでは、参考にすべきいくつかの効果的な Node.js アプリのパターンについて説明します。

シングル vCPU App Service プランを選択する

App Serviceプランを使う関数アプリを作成する際は、複数のvCPUプランではなく、単一のvCPUプランを選択してください。 現在、FunctionsはシングルvCPUのVM上で Node.js 関数をより効率的に動作させ、より大きなVMを使うことで期待された性能向上は得られません。 必要に応じて、単一vCPUのVMインスタンスを追加してスケールアウトするか、オートスケーリングを有効にすることもできます。 詳細については、「手動または自動によるインスタンス数のスケール変更」を参照してください。

パッケージ ファイルから実行する

サーバーレス ホスティング モデルでAzure Functionsを開発する場合、コールド スタートが現実になります。 "コールド スタート" とは、非アクティブな期間の後で初めて関数アプリが起動するとき、起動に時間がかかることを意味します。 特に、大きな依存関係ツリーを持つ Node.js アプリの場合は、コールド スタートが重要になる可能性があります。 コールド スタート プロセスをスピードアップするには、可能な場合、パッケージ ファイルとして関数を実行します。 多くの展開方法はデフォルトでこのモデルを採用していますが、大規模なコールドスタートが発生している場合は、この方法で運用しているか確認してください。

asyncawait を使用する

Node.jsでAzure Functionsを書く際は、asyncawaitキーワードを使ってコードを書いてください。 コールバックやasyncawait with Promisesの代わりに.then.catchを使ってコードを書くことで、2つの一般的な問題を回避できます。

  • Node.js プロセスをクラッシュさせる、キャッチされない例外のスロー。他の関数の実行に影響する可能性があります。
  • 適切に待機しない非同期呼び出しによって発生する、context.log からのログの欠落などの予期しない動作。

次の例では、非同期メソッド fs.readFile が、その 2 番目のパラメーターとしてエラーファースト コールバック関数を使用して呼び出されています。 このコードは、前述した両方の問題の原因となります。 正しいスコープでは明示的にキャッチされない例外によって、プロセス全体がクラッシュする可能性があります (問題 1)。 コールバックが完了したことを確認することなく戻ると、HTTP応答が空の本体になることがある(問題#2)。

// DO NOT USE THIS CODE
const { app } = require('@azure/functions');
const fs = require('fs');

app.http('httpTriggerBadAsync', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        let fileData;
        fs.readFile('./helloWorld.txt', (err, data) => {
            if (err) {
                context.error(err);
                // BUG #1: This will result in an uncaught exception that crashes the entire process
                throw err;
            }
            fileData = data;
        });
        // BUG #2: fileData is not guaranteed to be set before the invocation ends
        return { body: fileData };
    },
});

次の例では、非同期メソッド fs.readFile が、その 2 番目のパラメーターとしてエラーファースト コールバック関数を使用して呼び出されています。 このコードは前述の2つの問題を引き起こします。 正しいスコープに明示的に捉えられていない例外は、プロセス全体をクラッシュさせる可能性があります(問題#1)。 廃止された context.done() メソッドをコールバックの範囲外で呼び出すと、関数がファイル読み取り前に完了したことを示すことがあります(問題#2)。 この例では、context.done() の呼び出しが早すぎるため、結果として Data from file: で始まるログ エントリが欠落します。

// NOT RECOMMENDED PATTERN
const fs = require("fs");

module.exports = function (context) {
  fs.readFile("./hello.txt", (err, data) => {
    if (err) {
      context.log.error("ERROR", err);
      // BUG #1: This will result in an uncaught exception that crashes the entire process
      throw err;
    }
    context.log(`Data from file: ${data}`);
    // context.done() should be called here
  });
  // BUG #2: Data is not guaranteed to be read before the Azure Function's invocation ends
  context.done();
};

asyncawaitキーワードを使って、これらの問題を回避しましょう。 Node.js エコシステムのほとんどのAPIは、何らかの形で約束をサポートしています。 例えば、バージョン14から Node.js はfs/promisesコールバックAPIを置き換えるfsAPIを提供しています。

次の例では、関数の実行中にスローされたハンドルされない例外により、例外を発生させた個々の呼び出しのみが失敗します。 await キーワードは、readFile に続くステップが、完了後にのみ実行されることを意味しています。

// Recommended pattern
const { app } = require('@azure/functions');
const fs = require('fs/promises');

app.http('httpTriggerGoodAsync', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        try {
            const fileData = await fs.readFile('./helloWorld.txt');
            return { body: fileData };
        } catch (err) {
            context.error(err);
            // This rethrown exception will only fail the individual invocation, instead of crashing the whole process
            throw err;
        }
    },
});

asyncawaitを使う場合は、context.done()コールバックを呼ぶ必要はありません。

// Recommended pattern
const fs = require("fs/promises");

module.exports = async function (context) {
  let data;
  try {
    data = await fs.readFile("./hello.txt");
  } catch (err) {
    context.log.error("ERROR", err);
    // This rethrown exception will be handled by the Functions Runtime and will only fail the individual invocation
    throw err;
  }
  context.log(`Data from file: ${data}`);
};

トラブルシューティング

Node.js のトラブルシューティング ガイド」を参照してください。

次のステップ

詳細については、次のリソースを参照してください。