演習 - 関数アプリにロジックを追加する

完了

引き続き歯車駆動の例を使用し、温度サービス用のロジックを追加しましょう。 具体的には、HTTP 要求からデータを受信します。

関数の要件

まず、ロジックにいくつかの要件を定義する必要があります。

  • 0 から 25 度の温度には、OK のフラグを設定します。
  • 25 から 50 度の温度には、CAUTION (注意) のフラグを設定します。
  • 50 度以上の温度には、[危険] のフラグを設定します。

関数アプリに関数を追加する

前のユニットで説明したように、Azure には関数のビルドに役立つテンプレートが用意されています。 このユニットでは、HttpTrigger テンプレートを使用して、温度サービスを実装します。

  1. 前の演習で、関数アプリをデプロイし、それを開きました。 まだ開いていない場合は、[ホーム] ページで [すべてのリソース] を選択し、ご自分の関数アプリ (escalator-functions-xxx のような名前) を選択して開くことができます。

  2. [関数アプリ] メニューで、[関数] の下の [関数] を選択します。 [関数] ペインが表示されます。 ご自分の関数アプリに定義したすべての関数が一覧表示されます。

  3. コマンド バーの [作成] を選択します。 [関数の作成] ペインが表示されます。

  4. [テンプレートの選択] で、[HTTP トリガー] を選択します。

  1. [作成] を選択します HttpTrigger1 が作成され、HttpTrigger1 関数ペインに表示されます。

  2. 左側の [開発者] メニューで、[コードとテスト] を選択します。 コード エディターが開き、関数の index.js コード ファイルの内容が表示されます。 HTTP テンプレートによって生成された既定のコードが、次のスニペット内に表示されます。

    module.exports = async function (context, req) {
        context.log('JavaScript HTTP trigger function processed a request.');
    
        const name = (req.query.name || (req.body && req.body.name));
        const responseMessage = name
            ? "Hello, " + name + ". This HTTP triggered function executed successfully."
            : "This HTTP triggered function executed successfully. Pass a name on the query string or in the request body for a personalized response.";
    
        context.res = {
            // status: 200, /* Defaults to 200 */
            body: responseMessage
        };
    }
    

    この関数は、HTTP 要求のクエリ文字列から、または要求本文の一部として名前が渡されることを想定しています。 この関数の応答で、"Hello, <name>. This HTTP triggered function executed successfully." (name さん、この HTTP トリガー関数は正常に実行されました。) というメッセージが返されます。このとき、要求で送信された name がエコー バックされます。

    ソース ファイルのドロップダウン リストから function.json を選択すると、次のコードのような関数の構成が表示されます。

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

    この構成ファイルで、HTTP 要求を受け取ったときに実行する関数を宣言します。 出力バインディングでは、HTTP 応答として送信される応答を宣言します。

  1. [テンプレートの詳細] セクションの [新しい関数] フィールドに、「DriveGearTemperatureService」と入力します。 [承認レベル][関数] のままにして [作成] 選択し、関数を作成します。 DriveGearTemperatureService 関数の [概要] ペインが表示されます。

  2. [関数] メニューで、[Code + Test](コードとテスト) を選択します。 コード エディターが開き、run.ps1 コード ファイルの内容が表示されます。 テンプレートによって生成された既定のコードは、次のスニペット内に一覧表示されます。

    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
    }
    
    $body = "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
    
    if ($name) {
        $body = "Hello, $name. This HTTP triggered function executed successfully."
    }
    
    # Associate values to output bindings by calling 'Push-OutputBinding'.
    Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
        StatusCode = [HttpStatusCode]::OK
        Body = $body
    })
    

    この関数は、HTTP 要求のクエリ文字列から、または要求本文の一部として名前が渡されることを想定しています。 HTTP 関数では、出力バインディングに書き込むことによって応答を生成する必要があります。これは、Push-OutputBinding コマンドレットを使用して PowerShell 関数で実行されます。 この関数では、メッセージ Hello $name が返され、要求で送信された名前がエコー バックされます。

  3. ソースのドロップダウン リストで function.json を選択すると、次のような関数の構成が表示されます。

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

    この構成では、HTTP 要求を受け取ったときに実行する関数を宣言します。 出力バインディングでは、HTTP 応答として送信される応答を宣言します。

関数をテストする

ヒント

cURL は、ファイルを送受信するために使用できるコマンドライン ツールです。 このツールは、Linux、macOS、および Windows 10 に含まれており、その他のほとんどのオペレーティング システムでもダウンロードできます。 cURL では、HTTP、HTTPS、FTP、FTPS、SFTP、LDAP、TELNET、SMTP、POP3 などのさまざまなプロトコルがサポートされます。 詳細については、次のリンクを参照してください。

関数をテストするには、コマンド ラインで cURL を使用して、関数 URL に HTTP 要求を送信できます。

  1. トリガー関数ペインの下部にある [ログ] フレームを展開します。 ログ フレームは、1 分ごとのトレース通知の取得を開始する必要があります。

  2. 関数のエンドポイント URL を確認するには、次の画像に示すように、コマンド バーで [関数の URL の取得] を選択します。 URL の末尾にある [クリップボードにコピー] アイコンを選択して、このリンクを保存します。 このリンクを後で使用できるように、メモ帳または同様のアプリに保存します。

    [関数の URL の取得] ボタンが強調表示されている関数エディターが示されている Azure portal のスクリーンショット。

HTTP トリガーをセキュリティで保護する

HTTP トリガーを使用すると、API キーを使用して、要求の一部としてキーを要求することによって、不明な呼び出し元をブロックすることができます。 関数を作成するときは、認証レベルを選択します。 既定では、これは関数固有の API キーが必要な "関数" に設定されますが、グローバルな "マスター" キーを使用するために "管理者" を設定したり、キーが必要ないことを示すために "匿名" を設定したりすることもできます。 作成後に関数プロパティから認証レベルを変更することもできます。

この関数を作成したときに "関数" を指定しているため、HTTP 要求を送信するときにキーを指定する必要があります。 これは、code という名前のクエリ文字列パラメーターとして、または x-functions-key という名前の HTTP ヘッダー (推奨) として送信できます。

  1. 関数とマスター キーを検索するには、Function App のメニューで [開発者] の下にある [関数キー] を選びます。 関数の [関数キー] ペインが開きます。

  2. 既定では、関数キー値は非表示です。 [値][Hidden value. Click to show value](非表示の値です。値を表示するには、クリックしてください) を選んで既定の関数キー値を表示します。 後で使うことができるように、値をクリップボードにコピーし、メモ帳などのアプリにこのキーを保存します。

    表示された関数キーが取り上げられている [関数キー] ペインを示すスクリーンショット。

  3. 画面の下部で、左にスクロールして自分の関数を選択します。 上部の [関数の URL の取得] セクションで、URL の最後にある [クリップボードにコピー] アイコンを選択して URL をコピーします。 このリンクを後で使用できるように、メモ帳または同様のアプリに保存します。

  4. 次に、左にスクロールし、Function App のメニューから [関数] の下にある [関数] を選び、HttpTrigger1 (PowerShell の場合は DriveGearTemperatureService) を選びます。 HttpTrigger1 (PowerShell の場合は DriveGearTemperatureService) 関数ペインが表示されます。

  5. 左側のメニュー ウィンドウの [開発者] で、[コードとテスト] を選択します。 HttpTrigger1 (PowerShell の場合は DriveGearTemperatureService) 関数の [Code + Test](コードとテスト) ペインが表示されます。

  6. コマンド バーの [Test/Run](テストと実行) を選びます。 テストを実行するための入力パラメーターを示すペイン。

  7. [本文] テキスト ボックスで、[本文] の 2 行目を次の cURL コマンドに置き換え、<your-function-key> を保存した関数キー値に置き換え、<your-https-url> を関数の URL に置き換えて、埋め込みコードを上書きします。

    curl --header "Content-Type: application/json" --header "x-functions-key: <your-function-key>" --request POST --data "{\"name\": \"Azure Function\"}" <your-https-url>
    
  8. cURL コマンドを見直し、次の値があることを確認します。

    • application/json の種類の Content-Type ヘッダー値が追加されていること。
    • 関数キーがヘッダー値 x-functions-key として渡されていること。
    • POST 要求が使用されていること。
    • 関数の URL で Azure 関数を渡しました。
  9. [実行] を選択します。

    [コードとテスト] ペインにセッションが開かれ、ログ ファイルの出力が表示されます。 ログ ファイルは要求の状態で更新され、JavaScript の場合は次のようになります。

    2022-02-16T22:34:10.473 [Information] Executing 'Functions.HttpTrigger1' (Reason='This function was programmatically called via the host APIs.', Id=4f503b35-b944-455e-ba02-5205f9e8b47a)
    2022-02-16T22:34:10.539 [Information] JavaScript HTTP trigger function processed a request.
    2022-02-16T22:34:10.562 [Information] Executed 'Functions.HttpTrigger1' (Succeeded, Id=4f503b35-b944-455e-ba02-5205f9e8b47a, Duration=114ms)
    

    PowerShell の場合は、次のようになります。

    2022-02-16T21:07:11.340 [Information] INFORMATION: PowerShell HTTP trigger function processed a request.
    2022-02-16T21:07:11.449 [Information] Executed 'Functions.DriveGearTemperatureService' (Succeeded, Id=25e2edc3-542f-4629-a152-cf9ed99680d8, Duration=1164ms)
    

    [出力] ウィンドウの、[HTTP 応答コード] に対して、関数がテキスト 200 OK で応答します。

    注意事項

    Windows を使用している場合は、コマンド プロンプトから cURL を実行してください。 PowerShell には curl コマンドがありますが、それは Invoke-WebRequest の別名であり、cURL と同じものではありません。

    注意

    コードとテスト関数によって、[Input/Output](入力と出力) ペインが別の構成で開かれ、選んだ関数の側にログ ファイルが表示されることがあります。 その場合、関数キー システムが動作していることは必須ではないため、確認することができません。 テスト インターフェイスで適切なヘッダーとパラメーターの値を追加し、[実行] を選択してテスト出力を表示します。

関数にビジネス ロジックを追加する

受け取った測定温度を確認し、各温度の読み取りの状態を設定する関数にロジックを追加しましょう。

この関数では、温度測定値の配列が要求されます。 次の JSON スニペットは、この関数に送信する要求本文の例です。 reading エントリごとに、ID、タイムスタンプ、温度があります。

{
    "readings": [
        {
            "driveGearId": 1,
            "timestamp": 1534263995,
            "temperature": 23
        },
        {
            "driveGearId": 3,
            "timestamp": 1534264048,
            "temperature": 45
        },
        {
            "driveGearId": 18,
            "timestamp": 1534264050,
            "temperature": 55
        }
    ]
}

ビジネス ロジックを実装するため、関数内の既定のコードを次のコードに置き換えましょう。

[HttpTrigger1] 関数ペインで index.js ファイルを開き、次のコードで置き換えます。 この変更を加えた後、コマンド バーの [保存] を選び、更新内容をファイルに保存します。

module.exports = function (context, req) {
    context.log('Drive Gear Temperature Service triggered');
    if (req.body && req.body.readings) {
        req.body.readings.forEach(function(reading) {

            if(reading.temperature<=25) {
                reading.status = 'OK';
            } else if (reading.temperature<=50) {
                reading.status = 'CAUTION';
            } else {
                reading.status = 'DANGER'
            }
            context.log('Reading is ' + reading.status);
        });

        context.res = {
            // status: 200, /* Defaults to 200 */
            body: {
                "readings": req.body.readings
            }
        };
    }
    else {
        context.res = {
            status: 400,
            body: "Please send an array of readings in the request body"
        };
    }
    context.done();
};

ここで追加したロジックは簡単です。 配列を反復処理し、温度フィールドの値に応じて OKCAUTIONDANGER のいずれかの状態を設定します。 次に、各エントリに追加された状態フィールドと共に、測定値の配列を返します。

ペインの下部にある [ログ] を展開するときは、Log ステートメントに注意してください。 関数が実行されると、これらのステートメントによって [ログ] ウィンドウにメッセージが追加されます。

run.ps1 ファイルを開き、その内容を次のコードに置き換えます。 この変更を加えた後、コマンド バーの [保存] を選び、更新内容をファイルに保存します。

using namespace System.Net

param($Request, $TriggerMetadata)

Write-Host "Drive Gear Temperature Service triggered"

$readings = $Request.Body.Readings
if ($readings) {
    foreach ($reading in $readings) {
        if ($reading.temperature -le 25) {
            $reading.Status = "OK"
        }
        elseif ($reading.temperature -le 50) {
            $reading.Status = "CAUTION"
        }
        else {
            $reading.Status = "DANGER"
        }

        Write-Host "Reading is $($reading.Status)"
    }

    $status = [HttpStatusCode]::OK
    $body = $readings
}
else {
    $status = [HttpStatusCode]::BadRequest
    $body = "Please send an array of readings in the request body"
}

Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = $status
    Body = $body
})

ここで追加したロジックは簡単です。 配列を反復処理し、温度フィールドの値に応じて OKCAUTIONDANGER のいずれかの状態を設定します。 次に、各エントリに追加された状態フィールドと共に、測定値の配列を返します。

Write-Host コマンドレットへの呼び出しに注意してください。 関数が実行されると、これらのステートメントによって [ログ] ウィンドウにメッセージが追加されます。

ビジネス ロジックをテストする

ここでは、[開発者]>[Code + Test]\(コードとテスト\)[Test/Run]\(テストと実行\) 機能を使い、関数をテストします。

  1. [入力] タブで [本文] テキスト ボックスの内容を次のコードに置き換えて、サンプル要求を作成します。

    {
        "readings": [
            {
                "driveGearId": 1,
                "timestamp": 1534263995,
                "temperature": 23
            },
            {
                "driveGearId": 3,
                "timestamp": 1534264048,
                "temperature": 45
            },
            {
                "driveGearId": 18,
                "timestamp": 1534264050,
                "temperature": 55
            }
        ]
    }
    
  2. [実行] を選択します。 [出力] タブに HTTP 応答コードと内容が表示されます。 ログ メッセージを表示するには、ウィンドウの下部にあるポップアップで [ログ] タブを開きます (まだ開かれていない場合)。 次の画像には、出力ペインに応答の例、[ログ] ペインにメッセージが示されています。

    Azure 関数エディターに [テスト] タブと [ログ] タブが表示されているスクリーンショット。

    [出力] タブは、状態フィールドが各測定値に正しく追加されたことを示しています。

  3. 左側の [開発者] メニューで [モニター] を選択し、要求が Application Insights にログ記録されていることを確認します。 関数の [監視] ペインが表示されます。

  4. [構成] をクリックします。 トリガー関数の [Application Insights] ペインが表示されます。

  5. [新しいリソースの作成] を選択し、[新しいリソース名] フィールドで関数アプリを選択し、[場所] フィールドで関数アプリに最初に関連付けたリージョンを選択します。

  6. [OK] を選択します。