Visual Studio Code を使用して Azure Functions を Azure Storage に接続する

Azure Functions を使用すると、独自の統合コードを記述しなくても、Azure サービスやその他のリソースを関数に接続できます。 これらのバインドは、入力と出力の両方を表し、関数定義内で宣言されます。 バインドからのデータは、パラメーターとして関数に提供されます。 "トリガー" は、特殊な種類の入力バインドです。 関数はトリガーを 1 つしか持てませんが、複数の入力および出力バインドを持つことができます。 詳細については、「Azure Functions でのトリガーとバインドの概念」を参照してください。

この記事では、Visual Studio Code を使用して、前のクイックスタート記事で作成した関数に Azure Storage を接続する方法について説明します。 この関数に追加する出力バインドは、HTTP 要求のデータを Azure Queue storage キュー内のメッセージに書き込みます。

ほとんどのバインドでは、バインドされているサービスにアクセスするために関数が使用する、保存されている接続文字列が必要です。 作業を簡単にするために、関数アプリで作成したストレージ アカウントを使用します。 このアカウントへの接続は、既に AzureWebJobsStorage という名前のアプリ設定に保存されています。

Note

現在、この記事でサポートされているのは Node.js v3 for Functions シナリオのみです。

ローカル環境を構成する

操作を始める前に、以下の要件を満たしておく必要があります。

  • Visual Studio Code 用の Azure Storage 拡張機能をインストールする。

  • Azure Storage Explorer をインストールする。 Storage Explorer は、出力バインドによって生成されるキュー メッセージの調査に使用するツールです。 Storage Explorer は、macOS、Windows、Linux ベースのオペレーティング システムでサポートされます。

この記事では、Visual Studio Code から Azure サブスクリプションに既にサインインしていることを前提としています。 コマンド パレットから Azure: Sign In を実行するとサインインできます。

関数アプリの設定をダウンロードする

前のクイックスタートの記事では、必要なストレージ アカウントと共に Azure で関数アプリを作成しました。 このアカウントの接続文字列は、Azure のアプリ設定に安全に格納されています。 この記事では、同じアカウントのストレージ キューにメッセージを書き込みます。 関数をローカルで実行しているときにストレージ アカウントに接続するには、アプリ設定を local.settings.json ファイルにダウンロードする必要があります。

  1. F1 キーを押してコマンド パレットを開き、コマンド Azure Functions: Download Remote Settings... を検索して実行します。

  2. 前の記事で作成した関数アプリを選択します。 [すべてはい] を選択して既存のローカル設定を上書きします。

    重要

    local.settings.json ファイルは、機密情報が含まれているため、公開されることはなく、ソース管理から除外されます。

  3. ストレージ アカウントの接続文字列値のキーである AzureWebJobsStorage の値をコピーします。 この接続を使用して、出力バインドが期待どおりに動作することを確認します。

バインディング拡張機能を登録する

Queue storage の出力バインドを使用しているため、このプロジェクトを実行する前に Storage のバインド拡張機能をインストールしておく必要があります。

プロジェクトは、拡張機能バンドルを使用するように構成されています。これにより、事前定義された一連の拡張機能パッケージが自動的にインストールされます。

拡張機能バンドルは、プロジェクトのルートにある host.json ファイルで次の例のように既に有効になっています。

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

これで、Storage の出力バインドをプロジェクトに追加できるようになります。

HTTP トリガーとタイマー トリガーを除き、バインドは拡張機能パッケージとして実装されます。 ターミナル ウィンドウで次の dotnet add package コマンドを実行して、Storage 拡張機能パッケージをプロジェクトに追加します。

dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues --prerelease

これで、Storage の出力バインドをプロジェクトに追加できるようになります。

出力バインディングを追加する

Functions では、各種のバインドで directiontype、固有の name が必要です。 これらの属性を定義する方法は、関数アプリの言語によって異なります。

バインド属性は、特定の関数の function.json ファイルで定義されます。 バインドの種類によっては、追加のプロパティが必要になることもあります。 キュー出力構成では、Azure Storage キュー バインドに必要なフィールドについて説明されています。 この拡張機能により、バインドを簡単に function.json ファイルに追加できます。

バインドを作成するには、HttpTrigger フォルダー内の function.json ファイルを右クリック (macOS では Ctrl キーを押しながらクリック) して、 [バインドの追加] を選択します。プロンプトに従って、新しいバインドの次のバインド プロパティを定義します。

Prompt 説明
Select binding direction (バインド方向を選択する) out バインドは出力バインドです。
Select binding with direction... (方向を使用してバインドを選択する...) Azure Queue Storage バインドは Azure Storage キュー バインドです。
コードでこのバインドの特定に使用する名前 msg コードで参照されているバインド パラメーターを識別する名前。
メッセージの送信先のキュー outqueue バインドが書き込むキューの名前。 queueName が存在しない場合は、バインドによって最初に使用されるときに作成されます。
Select setting from "local.setting.json" ("local.setting.json" から設定を選択する) AzureWebJobsStorage ストレージ アカウントの接続文字列を含むアプリケーション設定の名前。 AzureWebJobsStorage 設定には、関数アプリで作成したストレージ アカウントの接続文字列が含まれています。

バインドは、function.jsonbindings 配列に追加されます。これは次のようになります。

{
  "type": "queue",
  "direction": "out",
  "name": "msg",
  "queueName": "outqueue",
  "connection": "AzureWebJobsStorage"
}

バインド属性は、function_app.py ファイル内の特定の関数コードを修飾することによって定義されます。 queue_output デコレーターを使用して、Azure Queue Storage 出力バインドを追加します。

queue_output デコレーターを使用すると、バインドの方向は暗黙的に "出力" になり、種類は Azure Storage Queue です。 HttpExample\function_app.py の関数コードに次のデコレーターを追加します。

@app.queue_output(arg_name="msg", queue_name="outqueue", connection="AzureWebJobsStorage")

このコードでは、arg_name は、コードで参照されているバインド パラメーターを示しています。queue_name はバインドからの書き込み先キューの名前で、connection はストレージ アカウントの接続文字列を含むアプリケーション設定の名前です。 クイック スタートでは、AzureWebJobsStorage 設定にある関数アプリと同じストレージ アカウントを使用します。 queue_name が存在しない場合は、バインドによって最初に使用されるときに作成されます。

C# プロジェクトでは、バインドは関数メソッドのバインド属性として定義されます。 具体的な定義は、お使いのアプリがインプロセス (C# クラス ライブラリ) で実行されるのか、分離ワーカー プロセスで実行されるのかによって異なります。

HttpExample.cs プロジェクト ファイルを開き、次の MultiResponse クラスを追加します。

public class MultiResponse
{
    [QueueOutput("outqueue",Connection = "AzureWebJobsStorage")]
    public string[] Messages { get; set; }
    public HttpResponseData HttpResponse { get; set; }
}

MultiResponse クラスを使用すると、outqueue という名前のストレージ キューと HTTP 成功メッセージに書き込むことができます。 QueueOutput 属性は文字列配列に適用されるので、複数のメッセージをキューに送信できます。

ストレージ アカウントの接続文字列は Connection プロパティによって設定されます。 この例では、既定のストレージ アカウントを既に使用しているため、Connection を省略してもかまいません。

Java プロジェクトでは、バインドは関数メソッドのバインド注釈として定義されます。 その後、これらの注釈に基づいて function.json ファイルが自動的に生成されます。

src/main/java の下の対象の関数コードの場所を参照し、Function.java プロジェクト ファイルを開きます。run メソッド定義に、次のパラメーターを追加します。

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

msg パラメーターは OutputBinding<T> 型です。これは、関数の完了時に出力バインドにメッセージとして書き込まれる文字列のコレクションを表します。 この場合、出力は outqueue という名前のストレージ キューです。 このストレージ アカウントの接続文字列は、connection メソッドによって設定されます。 接続文字列自体ではなく、ストレージ アカウントの接続文字列を含むアプリケーション設定を渡します。

run メソッドの定義は次の例のようになります。

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

出力バインディングを使用するコードを追加する

バインドが定義されたら、そのバインドの name を使用して、関数シグネチャの属性としてアクセスできます。 出力バインドを使用すると、認証、キュー参照の取得、またはデータの書き込みに、Azure Storage SDK のコードを使用する必要がなくなります。 Functions ランタイムおよびキューの出力バインドが、ユーザーに代わってこれらのタスクを処理します。

context.bindingsmsg 出力バインド オブジェクトを使用してキュー メッセージを作成するコードを追加します。 このコードを context.res ステートメントの前に追加します。

// Add a message to the Storage queue,
// which is the name passed to the function.
context.bindings.msg = (req.query.name || req.body.name);

この時点で、関数は次のようになります。

module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');

    if (req.query.name || (req.body && req.body.name)) {
        // Add a message to the Storage queue,
        // which is the name passed to the function.
        context.bindings.msg = (req.query.name || req.body.name);
        context.res = {
            // status: 200, /* Defaults to 200 */
            body: "Hello " + (req.query.name || req.body.name)
        };
    }
    else {
        context.res = {
            status: 400,
            body: "Please pass a name on the query string or in the request body"
        };
    }
};

context.bindingsmsg 出力バインド オブジェクトを使用してキュー メッセージを作成するコードを追加します。 このコードを context.res ステートメントの前に追加します。

context.bindings.msg = name;

この時点で、関数は次のようになるはずです。

import { AzureFunction, Context, HttpRequest } from "@azure/functions"

const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
    context.log('HTTP trigger function processed a request.');
    const name = (req.query.name || (req.body && req.body.name));

    if (name) {
        // Add a message to the storage queue, 
        // which is the name passed to the function.
        context.bindings.msg = name; 
        // Send a "hello" response.
        context.res = {
            // status: 200, /* Defaults to 200 */
            body: "Hello " + (req.query.name || req.body.name)
        };
    }
    else {
        context.res = {
            status: 400,
            body: "Please pass a name on the query string or in the request body"
        };
    }
};

export default httpTrigger;

Push-OutputBinding コマンドレットと msg 出力バインディングを使用してキューにテキストを書き込むコードを追加します。 if ステートメントで OK ステータスを設定する前に、このコードを追加してください。

$outputMsg = $name
Push-OutputBinding -name msg -Value $outputMsg

この時点で、関数は次のようになるはずです。

using namespace System.Net

# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)

# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."

# Interact with query parameters or the body of the request.
$name = $Request.Query.Name
if (-not $name) {
    $name = $Request.Body.Name
}

if ($name) {
    # Write the $name value to the queue, 
    # which is the name passed to the function.
    $outputMsg = $name
    Push-OutputBinding -name msg -Value $outputMsg

    $status = [HttpStatusCode]::OK
    $body = "Hello $name"
}
else {
    $status = [HttpStatusCode]::BadRequest
    $body = "Please pass a name on the query string or in the request body."
}

# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = $status
    Body = $body
})

次のコードに合わせて HttpExample\function_app.py を更新し、関数の定義に msg パラメーターを、if name: ステートメントの下に msg.set(name) を追加してください。

import azure.functions as func
import logging

app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)

@app.route(route="HttpExample")
@app.queue_output(arg_name="msg", queue_name="outqueue", connection="AzureWebJobsStorage")
def HttpExample(req: func.HttpRequest, msg: func.Out [func.QueueMessage]) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    name = req.params.get('name')
    if not name:
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            name = req_body.get('name')

    if name:
        msg.set(name)
        return func.HttpResponse(f"Hello, {name}. This HTTP triggered function executed successfully.")
    else:
        return func.HttpResponse(
             "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.",
             status_code=200
        )

msg パラメーターは、azure.functions.Out class のインスタンスです。 set メソッドはキューに文字列メッセージを書き込みます。 この場合は、URL クエリ文字列の中で関数に渡される name です。

既存の HttpExample クラスを次のコードに置き換えます。

    [Function("HttpExample")]
    public static MultiResponse Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req,
        FunctionContext executionContext)
    {
        var logger = executionContext.GetLogger("HttpExample");
        logger.LogInformation("C# HTTP trigger function processed a request.");

        var message = "Welcome to Azure Functions!";

        var response = req.CreateResponse(HttpStatusCode.OK);
        response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
        response.WriteString(message);

        // Return a response to both HTTP trigger and storage output binding.
        return new MultiResponse()
        {
            // Write a single message.
            Messages = new string[] { message },
            HttpResponse = response
        };
    }
}

これで、新しい msg パラメーターを使用して、関数コードから出力バインドに書き込むことができます。 成功応答の前に次のコード行を追加して、name の値を msg 出力バインドに追加します。

msg.setValue(name);

出力バインドを使用すると、認証、キュー参照の取得、またはデータの書き込みに、Azure Storage SDK のコードを使用する必要がなくなります。 Functions ランタイムおよびキューの出力バインドが、ユーザーに代わってこれらのタスクを処理します。

run メソッドは次の例のようになります。

@FunctionName("HttpExample")
public HttpResponseMessage run(
        @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) 
        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();
    }
}

テストを更新する

アーキタイプはテストのセットも作成するため、run メソッド シグネチャ内の新しい msg パラメーターを処理するためにこれらのテストを更新する必要があります。

src/main/java の下の対象のテスト コードの場所を参照し、Function.java プロジェクト ファイルを開きます。//Invoke の下のコード行を次のコードに置き換えます。

@SuppressWarnings("unchecked")
final OutputBinding<String> msg = (OutputBinding<String>)mock(OutputBinding.class);
final HttpResponseMessage ret = new Function().run(req, msg, context);

関数をローカルで実行する

Visual Studio Code を Azure Functions Core Tools と統合することで、このプロジェクトをローカルの開発用コンピューター上で実行してから、Azure に発行することができます。 Core Tools をローカルにまだインストールしていない場合は、プロジェクトを初めて実行するときにインストールするように求められます。

  1. 関数を呼び出すには、F5 キーを押して関数アプリ プロジェクトを起動します。 ターミナル パネルに、Core Tools からの出力が表示されます。 アプリがターミナル パネルで起動します。 HTTP によってトリガーされる関数の URL エンドポイントがローカルで実行されていることを確認できます。

    ローカル関数の Visual Studio Code 出力のスクリーンショット。

    Core Tools をまだインストールしていない場合は、インストールを求められたら [インストール] を選択して、Core Tools をインストールします。
    Windows での実行に問題がある場合、Visual Studio Code の既定のターミナルが WSL Bash に設定されていないことをご確認ください。

  2. Core Tools を実行したまま、[Azure: Functions] 領域に移動します。 [Functions][ローカル プロジェクト]>[Functions] を展開します。 HttpExample 関数を右クリック (Windows) または Ctrl キーを押しながらクリック (macOS) して、[Execute Function Now]\(今すぐ関数を実行\) を選択します。

    Visual Studio Code の [今すぐ関数を実行] のスクリーンショット。

  3. [要求本文を入力してください] で、Enter キーを押して要求メッセージを関数に送信します。

  4. ローカルで関数を実行し、応答が返されると、Visual Studio Code で通知が発生します。 関数の実行に関する情報は、ターミナル パネルに表示されます。

  5. Ctrl + C キーを押して Core Tools を停止し、デバッガーの接続を解除します。

関数をローカルで実行する

  1. 前の記事と同様、F5 キーを押して関数アプリ プロジェクトと Core Tools を起動します。

  2. Core Tools を実行したまま、[Azure: Functions] 領域に移動します。 [Functions][ローカル プロジェクト]>[Functions] を展開します。 HttpExample 関数を右クリック (Mac では Ctrl キーを押しながらクリック) し、[Execute Function Now...] (今すぐ関数を実行...) を選択します。

    Visual Studio Code から関数を実行するスクリーンショット。

  3. [Enter request body] (要求本文を入力してください) に、要求メッセージ本文の値として { "name": "Azure" } が表示されます。 Enter キーを押して、この要求メッセージを関数に送信します。

  4. 応答が返されたら、Ctrl + C キーを押して Core Tools を停止します。

ストレージの接続文字列を使用しているため、ローカルで実行されている関数は Azure ストレージ アカウントに接続します。 出力バインディングを最初に使用するときに、outqueue という名前の新しいキューが、Functions ランタイムによってストレージ アカウントに作成されます。 このキューが新しいメッセージと共に作成されたことを確認するために、Storage Explorer を使用します。

ストレージ エクスプローラーをアカウントに接続する

既に Azure Storage Explorer をインストールして Azure アカウントに接続している場合は、このセクションをスキップしてください。

  1. Azure Storage Explorer ツールを実行し、左側の接続アイコンを選択して、 [アカウントの追加] を選択します。

    Microsoft Azure Storage Explorer に Azure アカウントを追加する方法のスクリーンショット。

  2. [接続] ダイアログで、[Add an Azure account] (Azure アカウントを追加する) を選択し、お使いの Azure 環境を選択して、[サインイン...] を選択します。

    Azure アカウント ウィンドウへのサインインのスクリーンショット。

自分のアカウントへのサインインが成功すると、そのアカウントに関連付けられている Azure サブスクリプションがすべて表示されます。 サブスクリプションを選択し、[エクスプローラーを開く] を選択します。

出力キューを確認する

  1. Visual Studio Code で、F1 キーを押してコマンド パレットを開き、コマンド Azure Storage: Open in Storage Explorer を検索して実行し、自分のストレージ アカウント名を選択します。 Azure Storage Explorer で自分のストレージ アカウントが開きます。

  2. [キュー] ノードを展開して、outqueue という名前のキューを選択します。

    このキューには、HTTP によってトリガーされる関数を実行したときにキューの出力バインディングが作成されたというメッセージが含まれます。 Azure の既定の name 値で関数を呼び出した場合、キュー メッセージは「Name passed to the function: Azure」(関数に渡された名前: Azure) になります。

    Azure Storage Explorer に表示されたキュー メッセージのスクリーンショット。

  3. 関数を再度実行し、別の要求を送信すると、キューに新しいメッセージが表示されます。

ここで、更新された関数アプリを Azure に再発行します。

更新したアプリを再デプロイして検証する

  1. Visual Studio Code で、F1 キーを押してコマンド パレットを開きます。 コマンド パレットで、Azure Functions: Deploy to function app... を検索して選択します。

  2. 最初の記事で作成した関数アプリを選択します。 同じアプリにプロジェクトを再デプロイしているため、 [デプロイ] を選択して、ファイルの上書きに関する警告を無視します。

  3. デプロイの完了後、もう一度 [Execute Function Now...] (今すぐ関数を実行...) 機能を使用して Azure で関数をトリガーできます。

  4. もう一度ストレージ キューのメッセージを表示して、出力バインドによってキューに新しいメッセージが再生成されていることを確認します。

リソースをクリーンアップする

Azure では、"リソース" とは、関数アプリ、関数、ストレージ アカウントなどのことを指します。 これらは "リソース グループ" に分類されており、グループを削除することでグループ内のすべてのものを削除できます。

これらのクイックスタートを完了するためにリソースを作成しました。 これらのリソースには、アカウントの状態サービスの価格に応じて課金される場合があります。 リソースの必要がなくなった場合にそれらを削除する方法を、次に示します。

  1. Visual Studio Code で、F1 キーを押してコマンド パレットを開きます。 コマンド パレットで、Azure: Open in portal を検索して選択します。

  2. 関数アプリを選択し、Enter キーを押します。 その関数アプリのページが Azure portal で開きます。

  3. [概要] タブで、 [リソース グループ] の横にある名前付きリンクを選択します。

    関数アプリのページから削除するリソース グループを選択するスクリーンショット。

  4. [リソース グループ] ページで、含まれているリソースの一覧を確認し、削除するものであることを確認します。

  5. [リソース グループの削除] を選択し、指示に従います。

    削除には数分かかることがあります。 実行されると、通知が数秒間表示されます。 ページの上部にあるベルのアイコンを選択して、通知を表示することもできます。

次のステップ

HTTP によってトリガーされる関数を、ストレージ キューにデータを書き込むように更新しました。 この後は、Visual Studio Code を使用した Functions の開発について理解を深めましょう。