Azure Functions の Node.js プログラミング モデルのバージョン 4 に移行する

この記事では、Node.js プログラミング モデルのバージョン 3 とバージョン 4 の違いと、既存の v3 アプリをアップグレードする方法について説明します。 既存の v3 アプリをアップグレードするのではなく、v4 アプリを新規に作成する場合は、Visual Studio Code (VS Code) または Azure Functions Core Tools のいずれかのチュートリアルを参照してください。 この記事では、「ヒント」アラートを使って、アプリをアップグレードする際に行うべき重要度の高い具体的なアクションを取り上げています。

バージョン 4 は、Node.js 開発者が次の利点を得られるように設計されています。

  • Node.js 開発者が慣れ親しんだ直感的なエクスペリエンスを提供する。
  • 完全なカスタマイズをサポートすることで、ファイル構造を柔軟にする。
  • 関数構成を定義するコード中心の方法に切り替える。

考慮事項

  • Node.js のプログラミング モデルと Azure Functions のランタイムを混同しないでください。
    • プログラミング モデル: コードの作成方法を定義します。JavaScript と TypeScript に固有です。
    • ランタイム: Azure Functions の基本的な動作を定義します。すべての言語で共有されます。
  • プログラミング モデルのバージョンは @azure/functions npm パッケージのバージョンに厳密に関連付けられています。 ランタイムとは別にバージョン管理されます。 ランタイムとプログラミング モデルの両方で最新のメジャー バージョン番号として 4 が使用されていますが、これは偶然です。
  • 同じ関数アプリ内で v3 と v4 のプログラミング モデルを混在させることはできません。 アプリに v4 関数を 1 つ登録するとすぐに、function.json ファイルに登録されているすべての v3 関数は無視されます。

必要条件

Node.js プログラミング モデルのバージョン 4 には、次の最小バージョンが必要です。

npm パッケージを含める

v4 で、Node.js プログラミング モデルを支援するプライマリ ソース コードが @azure/functions npm パッケージに含まれるようになりました。 以前のバージョンでは、このコードは Azure で直接リリースされ、npm パッケージには TypeScript 型のみが含まれていました。 今後は、TypeScript と JavaScript の両方のアプリでこのパッケージを含める必要があります。 既存の v3 アプリにこのパッケージを含めることは "できます" が、必須ではありません。

ヒント

package.json ファイルの dependencies セクション (devDependencies ではありません) に必ず @azure/functions パッケージを記載してください。 v4 は、次のコマンドを使用してインストールできます。

npm install @azure/functions

アプリのエントリ ポイントを設定する

プログラミング モデルの v4 では、コードを自由に構成できます。 アプリのルートに必要なファイルは、host.jsonpackage.json のみです。

それ以外については、package.json ファイルの main フィールドを設定することでファイル構造を定義します。 1 つのファイル、glob パターンを使って複数のファイルに main フィールドを設定できます。 main フィールドの一般的な値は次のとおりです。

  • TypeScript:
    • dist/src/index.js
    • dist/src/functions/*.js
  • JavaScript:
    • src/index.js
    • src/functions/*.js

ヒント

package.json ファイルには必ず main フィールドを定義します

引数の順序を入れ替える

関数ハンドラーの 1 つ目の引数は、呼び出しコンテキストではなくトリガー入力になりました。 呼び出しコンテキストは、v4 では 2 つ目の引数になり、簡略化されました。トリガー入力とは異なり、必須ではなくなりました。 使用していない場合は、オフにしておくことができます。

ヒント

引数の順序を入れ替えてください。 たとえば、HTTP トリガーを使っている場合、(context, request)(request, context) に切り替えるか、コンテキストを使わない場合は単に (request) にします。

コードで関数を定義する

これらの個別の function.json 構成ファイルを作成して維持する必要はなくなりました。 TypeScript または JavaScript ファイルで関数を直接完全に定義できるようになりました。 さらに、多くのプロパティには既定値が設定されているので、毎回指定する必要はありません。

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

app.http('helloWorld1', {
  methods: ['GET', 'POST'],
  handler: async (request, context) => {
    context.log('Http function processed request');

    const name = request.query.get('name') 
      || await request.text() 
      || 'world';

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

ヒント

構成を function.json ファイルからお使いのコードに移行します。 トリガーの種類は、新しいモデルの app オブジェクトのメソッドに対応します。 たとえば、function.jsonhttpTrigger 型を使う場合、コードで app.http() を呼び出して関数を登録するようにします。 timerTrigger を使用する場合は、app.timer() を呼び出します。

コンテキストの使い方を確認する

v4 では、context オブジェクトが簡略化され、重複が減り、単体テストの作成が容易になります。 たとえば、プライマリ入力と出力を整理し、関数ハンドラーの引数と戻り値としてのみアクセスするようにしました。

context オブジェクトでのプライマリ入力と出力にはアクセスできなくなりましたが、context オブジェクトでのセカンダリ入力と出力には引き続きアクセスする必要があります。 セカンダリ入力と出力の詳細については、Node.js 開発者向けガイドを参照してください。

引数としてプライマリ入力を取得する

プライマリ入力は「トリガー」とも呼ばれ、唯一の必要な入力または出力です。 使用できるのは 1 つのトリガーのみです。

バージョン 4 は、最初の引数としてトリガー入力を取得する以下の方法のみをサポートしています。

async function helloWorld1(request, context) {
  const onlyOption = request;

ヒント

入力の取得に context.reqcontext.bindings を使っていないことを確認してください。

プライマリ出力を戻り値として設定する

バージョン 4 は、戻り値を介してプライマリ出力を設定する方法のみをサポートしています。

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

ヒント

context オブジェクトを使って設定するのではなく、関数ハンドラーで常に出力を返すようにしてください。

テスト コンテキストを作成する

バージョン 3 は、Azure Functions Runtime の外部で呼び出しコンテキストを作成することをサポートしていないため、単体テストの作成が困難でした。 バージョン 4 では、呼び出しコンテキストのインスタンスを作成できますが、テスト中の情報は、自分で追加しない限り詳細ではありません。

const testInvocationContext = new InvocationContext({
  functionName: 'testFunctionName',
  invocationId: 'testInvocationId'
});

HTTP の型の使い方を確認する

HTTP 要求と応答の型は、fetch 標準のサブセットになりました。 これらは、Azure Functions に固有ではなくなりました。

型は、Node.js の undici パッケージを使用します。 このパッケージは fetch 標準に準拠し、現在は Node.js コアに統合されています。

HttpRequest

  • 本文。 受け取る型に応じたメソッドを使って、本文にアクセスできます。

      const body = await request.text();
      const body = await request.json();
      const body = await request.formData();
      const body = await request.arrayBuffer();
      const body = await request.blob();
    
  • ヘッダー:

    const header = request.headers.get('content-type');
    
  • クエリ パラメーター:

    const name = request.query.get('name');
    

HttpResponse

  • 状態:

    return { status: 200 };
    
  • 本文:

    return { body: "Hello, world!" };
    
  • ヘッダー。 ヘッダーは HttpResponse クラスと HttpResponseInit インターフェイスのどちらを使うかに応じて、2 つの方法で設定できます。

    const response = new HttpResponse();
    response.headers.set('content-type', 'application/json');
    return response;
    
    return {
      headers: { 'content-type': 'application/json' }
    };
    

ヒント

新しいメソッドに合わせて HTTP 要求または応答の型を使ってロジックを更新します。 TypeScript を使っている場合、古いメソッドを使うとビルド エラーが発生します。

トラブルシューティング

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