次の方法で共有


コマンド ライン ツールを使用してAzure FunctionsをAzure Storageに接続する

この記事では、前回のクイック スタート ガイドで作成した関数と Storage アカウントに Azure Storage キューを統合します。 この統合は、HTTP 要求からキュー内のメッセージにデータを書き込む "出力バインディング" を使用して実現します。 この記事を終えても、前のクイックスタートの数セント以外に余分なコストが発生することはありません。 バインディングの詳細については、「Azure Functions トリガーとバインドの概念を参照してください。

ローカル環境を構成する

開始する前に、記事「Quickstart: コマンド ラインから Azure Functions プロジェクトを作成する」を完了する必要があります。 その記事の最後にリソースを既にクリーンアップしている場合は、もう一度手順を実行して、Azureで関数アプリと関連リソースを再作成します。

開始する前に、クイックスタート: コマンドラインから Azure Functions プロジェクトを作成する を完了する必要があります。 その記事の最後にリソースを既にクリーンアップしている場合は、もう一度手順を実行して、Azureで関数アプリと関連リソースを再作成します。

開始する前に、クイックスタート: コマンドラインから Azure Functions プロジェクトを作成するを完了してください。 その記事の最後にリソースを既にクリーンアップしている場合は、もう一度手順を実行して、Azureで関数アプリと関連リソースを再作成します。

開始する前に、「クイックスタート: コマンドラインから Azure Functions プロジェクトを作成する」を完了する必要があります。 その記事の最後にリソースを既にクリーンアップしている場合は、もう一度手順を実行して、Azureで関数アプリと関連リソースを再作成します。

開始する前に、「クイックスタート: コマンドラインから Azure Functions プロジェクトを作成する」を完了させる必要があります。 その記事の最後にリソースを既にクリーンアップしている場合は、もう一度手順を実行して、Azureで関数アプリと関連リソースを再作成します。

開始する前に、「クイックスタート: コマンドラインから Azure Functions プロジェクトを作成する」の記事を完了する必要があります。 その記事の最後にリソースを既にクリーンアップしている場合は、もう一度手順を実行して、Azureで関数アプリと関連リソースを再作成します。

Azure Storage connection stringを取得する

重要

この記事では現在、共有秘密鍵を含むconnection stringを使用してAzure Storage アカウントに接続する方法について説明します。 connection stringを使用すると、storage アカウントでデータの更新を簡単に確認できます。 セキュリティを最大限に高めるためには、代わりにマネージド ID を使用して、storage アカウントに接続する必要があります。 詳しくは、開発者ガイドの「接続」をご覧ください。

前に、関数アプリで使用するAzure Storage アカウントを作成しました。 このアカウントのconnection stringは、Azureのアプリ設定に安全に保存されます。 local.settings.json ファイルに設定をダウンロードすると、関数をローカルで実行するときに、接続を使用して同じアカウント内のStorage キューに書き込むことができます。

  1. projectのルートから次のコマンドを実行し、<APP_NAME> を前の手順の関数アプリの名前に置き換えます。 このコマンドを実行すると、ファイル内の既存の値はすべて上書きされます。

    func azure functionapp fetch-app-settings <APP_NAME>
    
  2. local.settings.json ファイルを開き、Storage アカウント connection stringである AzureWebJobsStorage という名前の値を見つけます。 この記事の他のセクションでは、名前 AzureWebJobsStorage とconnection stringを使用します。

重要

local.settings.json ファイルにはAzureからダウンロードしたシークレットが含まれているため、常にソース管理からこのファイルを除外します。 ローカル関数プロジェクトを用いて作成された .gitignore ファイルは、既定でファイルを除外します。

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

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

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

これで、ストレージ出力バインディングをプロジェクトに追加できるようになりました。

出力バインディングの定義を関数に追加する

1 つの関数に含めることができるトリガーは 1 つだけですが、複数の入力バインドと出力バインドを持つことができます。これにより、カスタム統合コードを記述することなく、他のAzure サービスやリソースに接続できます。

Node.js v4 プログラミング モデルを使用する場合、バインド属性は ./src/functions/HttpExample.js ファイルで直接定義されます。 前のクイックスタートのファイルには、app.http メソッドによって定義された HTTP バインドが既に含まれています。

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

app.http('httpTrigger', {
  methods: ['GET', 'POST'],
  authLevel: 'anonymous',
  handler: async (request, context) => {
    try {
      context.log(`Http function processed request for url "${request.url}"`);

      const name = request.query.get('name') || (await request.text());
      context.log(`Name: ${name}`);

      if (!name) {
        return { status: 404, body: 'Not Found' };
      }

      return { body: `Hello, ${name}!` };
    } catch (error) {
      context.log(`Error: ${error}`);
      return { status: 500, body: 'Internal Server Error' };
    }
  },
});

Node.js v4 プログラミング モデルを使用する場合、バインド属性は ./src/functions/HttpExample.js ファイルで直接定義されます。 前のクイックスタートのファイルには、app.http メソッドによって定義された HTTP バインドが既に含まれています。

import {
  app,
  HttpRequest,
  HttpResponseInit,
  InvocationContext,
} from '@azure/functions';

export async function httpTrigger1(
  request: HttpRequest,
  context: InvocationContext,
): Promise<HttpResponseInit> {
  context.log(`Http function processed request for url "${request.url}"`);

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

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

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

関数フォルダーの function.json ファイルでそれらのバインディングを宣言します。 前のクイックスタートの HttpExample フォルダーにある function.json ファイルでは、bindings コレクション内に 2 つのバインディングが含まれています。

Python v2 プログラミング モデルを使用する場合、バインド属性はデコレーターとして function_app.py ファイル内で直接定義されます。 function_app.py ファイルには、前のクイック スタートからデコレーター ベースのバインドが既に 1 つ含まれています。

import azure.functions as func
import logging

app = func.FunctionApp()

@app.function_name(name="HttpTrigger1")
@app.route(route="hello", auth_level=func.AuthLevel.ANONYMOUS)

route デコレーターによって、HttpTrigger と HttpOutput バインドが関数に追加され、http 要求が指定されたルートに達したときに関数をトリガーできます。

この関数からAzure Storage キューに書き込むには、queue_output デコレーターを関数コードに追加します。

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

デコレーターでは、arg_name はコードで参照されるバインド パラメーターを識別し、queue_name はバインドが書き込むキューの名前、connection は、Storage アカウントのconnection stringを含むアプリケーション設定の名前です。 クイック スタートでは、関数アプリと同じstorage アカウントを使用します。これは、AzureWebJobsStorage 設定 (local.settings.json ファイルから) にあります。 queue_name が存在しない場合、バインドは初めて使用されるときにそれを作成します。

"bindings": [
  {
    "authLevel": "function",
    "type": "httpTrigger",
    "direction": "in",
    "name": "Request",
    "methods": [
      "get",
      "post"
    ]
  },
  {
    "type": "http",
    "direction": "out",
    "name": "Response"
  }
]

Azure Storage キューに書き込むには:

  • バインド構成に extraOutputs プロパティを追加する

    {
        methods: ['GET', 'POST'],
        extraOutputs: [sendToQueue], // add output binding to HTTP trigger
        authLevel: 'anonymous',
        handler: () => {}
    }
    
  • output.storageQueue 呼び出しの上に app.http 関数を追加する

    const sendToQueue: StorageQueueOutput = output.storageQueue({
      queueName: 'outqueue',
      connection: 'AzureWebJobsStorage',
    });
    

コレクションの 2 つ目のバインディングの名前は res です。 この http バインディングは、HTTP 応答の書き込みに使用される出力バインディング (out) です。

この関数からAzure Storage キューに書き込むには、次のコードに示すように、out という名前の queue 型の msg バインディングを追加します。

    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "Request",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "Response"
    },
    {
      "type": "queue",
      "direction": "out",
      "name": "msg",
      "queueName": "outqueue",
      "connection": "AzureWebJobsStorage"
    }
  ]
}

queue 型の場合は、queueName でキューの名前を指定し、Azure Storage接続のname (local.settings.json ファイルから) connection に指定する必要があります。

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

HttpExample.cs project ファイルを開き、次の MultiResponse クラスを追加します。

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

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

Connection プロパティは、storage アカウントのconnection stringを設定します。 この場合、既定のstorage アカウントを既に使用しているため、Connection を省略できます。

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

src/main/java で関数コードの場所を参照し、Function.java project ファイルを開き、run メソッド定義に次のパラメーターを追加します。

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

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

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

@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) {
    ...
}

バインドの詳細については、「Azure Functionsトリガーとバインドの概念およびキュー出力構成を参照してください。

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

キュー バインディングが定義されたら、msg 出力パラメーターを受け取ってメッセージをキューに書き込むように関数を更新することができます。

次のコードに合わせて HttpExample\function_app.py を更新し、関数の定義に msg パラメーターを、msg.set(name) ステートメントの下に if 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 です。

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

context.extraOutputs.set(sendToQueue, [msg]);

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

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

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

app.http('HttpExample', {
  methods: ['GET', 'POST'],
  authLevel: 'anonymous',
  extraOutputs: [sendToQueue],
  handler: async (request, context) => {
    try {
      context.log(`Http function processed request for url "${request.url}"`);

      const name = request.query.get('name') || (await request.text());
      context.log(`Name: ${name}`);

      if (name) {
        const msg = `Name passed to the function ${name}`;
        context.extraOutputs.set(sendToQueue, [msg]);
        return { body: msg };
      } else {
        context.log('Missing required data');
        return { status: 404, body: 'Missing required data' };
      }
    } catch (error) {
      context.log(`Error: ${error}`);
      return { status: 500, body: 'Internal Server Error' };
    }
  },
});

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

context.extraOutputs.set(sendToQueue, [msg]);

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

import {
  app,
  output,
  HttpRequest,
  HttpResponseInit,
  InvocationContext,
  StorageQueueOutput,
} from '@azure/functions';

const sendToQueue: StorageQueueOutput = output.storageQueue({
  queueName: 'outqueue',
  connection: 'AzureWebJobsStorage',
});

export async function HttpExample(
  request: HttpRequest,
  context: InvocationContext,
): Promise<HttpResponseInit> {
  try {
    context.log(`Http function processed request for url "${request.url}"`);

    const name = request.query.get('name') || (await request.text());
    context.log(`Name: ${name}`);

    if (name) {
      const msg = `Name passed to the function ${name}`;
      context.extraOutputs.set(sendToQueue, [msg]);
      return { body: msg };
    } else {
      context.log('Missing required data');
      return { status: 404, body: 'Missing required data' };
    }
  } catch (error) {
    context.log(`Error: ${error}`);
    return { status: 500, body: 'Internal Server Error' };
  }
}

app.http('HttpExample', {
  methods: ['GET', 'POST'],
  authLevel: 'anonymous',
  handler: HttpExample,
});

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
})

既存の Run メソッドを次のコードに置き換えます。

[Function("HttpExample")]
public MultiResponse Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req)
{
    _logger.LogInformation("C# HTTP trigger function processed a request.");

    var message = "Welcome to Azure Functions!";

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

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

msg.setValue(name);

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

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

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();
    }
}

テストを更新する

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

src/test/java でテスト コードの場所を参照し、Function.java project ファイルを開き、//Invoke のコード行を次のコードに置き換えます。

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

認証、キューの参照の取得、データの書き込みのためのコードを記述する必要が "ない" 点に注目してください。 これらすべての統合タスクは、Azure Functions ランタイムとキューの出力バインドで便利に処理されます。

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

  1. LocalFunctionProj フォルダーからローカル Azure Functions ランタイム ホストを起動して、関数を実行します。

    func start
    

    出力の終わりに、次の行が表示されている必要があります。

    関数をローカルで実行するときのターミナル ウィンドウ出力のスクリーンショット。

    HttpExample が上記のように表示されない場合は、projectのルート フォルダーの外部からホストを開始した可能性があります。 その場合は、Ctrl+C を使用してホストを停止し、projectのルート フォルダーに移動して、前のコマンドをもう一度実行します。

  2. この出力から HTTP 関数の URL をブラウザーにコピーし、クエリ文字列 ?name=<YOUR_NAME> を付加して、http://localhost:7071/api/HttpExample?name=Functions のような完全な URL にします。 ブラウザーには、クエリ文字列値をエコー バックする応答メッセージが表示されるはずです。 projectを開始したターミナルには、要求を行う際のログ出力も表示されます。

  3. 完了したら、Ctrl + C キーを押し、「y」を入力して関数ホストを停止してください。

Azure Storage キュー内のメッセージを表示する

キューは、Azure portal または Microsoft Azure Storage Explorer で表示できます。 次の手順で説明するように、Azure CLIでキューを表示することもできます。

  1. 関数projectの local.setting.json ファイルを開き、connection string値をコピーします。 ターミナルまたはコマンド ウィンドウで、次のコマンドを実行して AZURE_STORAGE_CONNECTION_STRING という名前の環境変数を作成し、<MY_CONNECTION_STRING>の代わりに特定のconnection stringを貼り付けます。 (この環境変数は、--connection-string 引数を使用して後続の各コマンドにconnection stringを指定する必要がないように意味します)。

    export AZURE_STORAGE_CONNECTION_STRING="<MY_CONNECTION_STRING>"
    
  2. (省略可能)az storage queue list コマンドを使用して、アカウント内のStorage キューを表示します。 このコマンドからの出力には、outqueue という名前のキューが含まれています。これはこのキューに対する最初のメッセージを関数が書き込んだときに作成されたものです。

    az storage queue list --output tsv
    
  3. az storage message get コマンドを使用して、このキューからメッセージを読み取ります。これは、前に関数をテストするときに指定した値である必要があります。 このコマンドは、キューから最初のメッセージを読み取って削除します。

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

    メッセージ本文は base64 エンコードに格納されるため、メッセージを表示する前にデコードする必要があります。 az storage message get を実行すると、メッセージはキューから削除されます。 outqueue にメッセージが 1 つしかない場合、このコマンドを 2 回目に実行したときにメッセージは取得されず、代わりにエラーが返されます。

Azureにprojectを再デプロイする

関数がメッセージを Azure Storage キューに書き込んだことをローカルで確認したら、projectを再デプロイして、Azureで実行されているエンドポイントを更新できます。

LocalFunctionsProj フォルダーで、func azure functionapp publish コマンドを使用してprojectを再デプロイし、<APP_NAME>をアプリの名前に置き換えます。

func azure functionapp publish <APP_NAME>

ローカル project フォルダーで、次の Maven コマンドを使用してprojectを再発行します。

mvn azure-functions:deploy

Azureで確認する

  1. 前のクイックスタートと同様、ブラウザーまたは CURL を使用して、再デプロイした関数をテストします。

    publish コマンドの出力に表示されている完全な呼び出し URL にクエリ パラメーター &name=Functions を追加して、ブラウザーのアドレス バーにコピーします。 関数をローカルで実行したときと同じ出力がブラウザーに表示されるはずです。

  2. 前のセクションで説明したように、Storage キューをもう一度調べて、キューに書き込まれた新しいメッセージが含まれていることを確認します。

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

終了した後、それ以上コストが発生しないよう、次のコマンドを使って、リソース グループとそこに含まれるすべてのリソースを削除します。

az group delete --name AzureFunctionsQuickstart-rg

次のステップ

HTTP トリガーの関数を更新して、データをストレージ キューに書き込むようにしました。 これで、Core Tools と Azure CLI を使用してコマンド ラインから Functions の開発の詳細を確認できます。