[アップデート] Amazon Connectの「Lambda関数を呼び出す」でパラメーターとレスポンスにJSONが使えるようになったので検証してみた

JSON形式が指定できるようになることで、何が変わるのか、変わらないのか、検証して考察してみました。
2023.04.08

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

みなさん、こんにちは!
福岡オフィスの青柳です。

Amazon Connectのコンタクトフローで「AWS Lambda関数を呼び出す」ブロックを使う際に、「入力パラメータ」および「出力レスポンス」それぞれに「JSON形式」が指定できるようになりました。

Amazon Connect launches expanded JSON attribute support in flows

これまでは、Lambda関数に渡す「入力パラメータ」も、Lambda関数から受け取る「出力レスポンス」も、いずれも「キーと値のペア」である必要がありました。
これが「JSON形式」でも指定できるようになったというアップデートです。

なお、今回のアップデートは正確には「AWS Lambda関数を呼び出す」ブロックと「ビューを表示」ブロックがJSONに対応したという内容なのですが、今回は「Lambda関数を呼び出す」ブロックについて使い方などを調査・検証しました。

(今回はLambda関数のランタイムとして「Node.js 18.x」を選択し、言語はJavaScriptを使用しました)

設定する箇所

「AWS Lambda関数を呼び出す」ブロックのプロパティにおいて、「入力パラメータ」の設定には「JSONを設定」、「出力レスポンス」の設定には「JSON」の選択肢がそれぞれ追加されています。

「入力パラメータ」の設定方法とLambda関数での参照方法

固定値を渡す方法

まず、JSONで使用可能な各「データ型」を使って、パラメータを指定してみます。

指定したJSONの内容:

{
    "keyNumber": 123,
    "keyString": "hoge",
    "keyBoolean": true,
    "keyNull": null,
    "keyObject": {
        "subKey1": "value1",
        "subKey2": "value2"
    },
    "keyArray": [
        "value3",
        "value4"
    ]
}

指定した入力パラメータは、これまでと同じく「イベントJSON」としてLambda関数へ渡されます。

上記の入力パラメータを指定した際のイベントJSONの内容は、以下のようになりました。

{
    "Details": {
        "ContactData": {
               :
            <省略>
               :
        },
        "Parameters": {
            "param1": {
                "keyNumber": 123,
                "keyString": "hoge",
                "keyBoolean": true,
                "keyNull": null,
                "keyObject": {
                    "subKey1": "value1",
                    "subKey2": "value2"
                },
                "keyArray": [
                    "value3",
                    "value4"
                ]
            }
        }
    },
    "Name": "ContactFlowEvent"
}

JSON内で使用した各データ型「数値型」「文字列型」「Boolean型」「Null型」が問題無くイベントJSONとしてLambda関数に渡っています。

また、JSONのネストされた構造型である「オブジェクト型」や、配列を使ったJSONについても、問題なく認識されています。

渡された入力パラメータをLambda関数のコード内で使用するには、以下のようにすればOKでした。

export const handler = async(event) => {
        :
    let value_number  = event['Details']['Parameters']['param1']['keyNumber'];
    let value_string  = event['Details']['Parameters']['param1']['keyString'];
    let value_boolean = event['Details']['Parameters']['param1']['keyBoolean'];
    let value_null    = event['Details']['Parameters']['param1']['keyNull'];
    let value_object  = event['Details']['Parameters']['param1']['keyObject']['subKey1'];
    let value_array   = event['Details']['Parameters']['param1']['keyArray'][0];
        :

注意点としては、JSONで渡したデータは、入力パラメータの「宛先キー」として指定したキー (今回の場合は「param1」) の配下にぶら下がるという点です。
(「Parameters」の直下に指定したJSONデータをぶら下げることはできないと思われます)

動的な値を渡す方法

Lambda関数を使って複雑な処理を行うためには、入力パラメータとして固定値のみではなく「コンタクト属性」を使って動的な値を渡す必要があります。

試しに、JSONを以下のように指定してみます。

{
    "key1": $.CustomerEndpoint.Address,
    "key2": $.Attributes.test
}

$.CustomerEndpoint.Addressはシステム属性「顧客の電話番号」を、$.Attributes.testはユーザー定義属性「test」をそれぞれ表します。
(もちろん、ユーザー定義属性「test」は定義済みの前提です)

このように指定したところ、「無効なJSON」と怒られてプロパティを保存することができませんでした。

そこで、以下のようにしてみました。

{
    "key1": "$.CustomerEndpoint.Address",
    "key2": "$.Attributes.test"
}

今度は受け付けてくれたようです。

このようにして「コンタクト属性」を使った入力パラメータを指定した場合、イベントJSONの内容は以下のようになりました。

{
    "Details": {
        "ContactData": {
               :
            <省略>
               :
        },
        "Parameters": {
            "param1": {
                "key1": "+81XXXXXXXXXX",
                "key2": "hogehoge"
            }
        }
    },
    "Name": "ContactFlowEvent"
}

ということで、動的な値を渡すのも問題無く行えるようです。

「出力レスポンス」の設定方法とコンタクトフローでの参照方法

今度は、Lambda関数の戻り値をコンタクトフローから「JSON形式」として参照する方法を検証します。

基本的なデータ型の場合

まずは、基本的なデータ型 (数値型、文字列型、ブール型、Null型) をLambda関数の戻り値として設定してみます。

export const handler = async(event) => {
    const response = {
        "keyNumber": 123,
        "keyString": "hoge",
        "keyBoolean": true,
        "keyNull": null
    };
    return response;
};

コンタクトフローでLambda関数の戻り値を参照する方法はいくつかあります。

1つ目の方法として、「コンタクト属性の設定」ブロック等でLambda関数の戻り値を「外部」属性として参照する方法を試してみます。

下図のようにして、「外部」属性の値を「ユーザー定義」属性への設定 (代入) します。

「外部」属性から「ユーザー定義」属性へ正しく値が代入できたかどうか、コンタクトフローのログで確認しましょう。
(ログのうち必要な部分のみを抜き出しています)

{
    "ContactFlowModuleType": "SetAttributes",
    "Parameters": {
        "Key": "valueNumber",
        "Value": "123"
    }
}

{
    "ContactFlowModuleType": "SetAttributes",
    "Parameters": {
        "Key": "valueString",
        "Value": "hoge"
    }
}

{
    "ContactFlowModuleType": "SetAttributes",
    "Parameters": {
        "Key": "valueBoolean",
        "Value": ""
    }
}

{
    "ContactFlowModuleType": "SetAttributes",
    "Parameters": {
        "Key": "valueNull",
        "Value": ""
    }
}

「数値型」「文字列型」は戻り値から正しく値を参照することができましたが、「ブール型」「Null型」は値を正しく参照することができませんでした。(値が設定されていない)

Lambda関数の戻り値を参照する2つ目の方法として、「プロンプトの再生」ブロック等で「$.External」記法を使って「外部」属性の参照を試みます。

テキスト中で以下のように記述することで「外部」属性の各値が参照できるはずです。

  • $.External.keyNumber
  • $.External.keyString
  • $.External.keyBoolean
  • $.External.keyNull

正しく値を参照できたか、コンタクトフローのログで確認しましょう。

{
    "ContactFlowModuleType": "PlayPrompt",
    "Parameters": {
        "TextToSpeechType": "text",
        "SpeakingStyle": "None",
        "Text": "1番目の値は 123 です。\n2番目の値は hoge です。\n3番目の値は  です。\n4番目の値は  です。",
        "Voice": "Kazuha",
        "GlobalEngine": "Neural"
    }
}

「数値型」「文字列型」の各値は正しく参照できました。
しかし、「ブール型」「Null型」は値を正しく参照することができませんでした。

(実際のプロンプト再生でも、「123」「hoge」は再生され、「true」「null」の部分は何も再生されないことが確認できると思います)

このように2つの方法を試しましたが、いずれの方法でも「ブール型」「Null型」の値は参照できないという結果になりました。

まあ、コンタクト属性には「データ型」の概念が無くブール型やNull型をそのまま扱うのは難しいと思いますので、これらのデータ型がLambda関数から受け取れないことはあまり問題にならないでしょう。

Lambda関数のコードを記述する際の注意点として、ブール型やNull型をそのまま戻り値に設定せず、文字列型にキャストするか、戻り値を文字列として返す (「"enable"」「"disable"」など) ことをお勧めします。

「オブジェクト型」の場合

今度は、「オブジェクト型」をデータ構造に持つJSONを戻り値に設定してみます。

export const handler = async(event) => {
    const response = {
        "keyObject": {
            "subKey1": "value1",
            "subKey2": "value2"
        }
    };
    return response;
};

「コンタクト属性の設定」ブロック等でLambda関数の戻り値を「外部」属性として参照するには、属性の名前をkeyObject.subkey1のように「キー名+"."+サブキー名」の形式で指定します。

コンタクトフローのログを確認すると、正しく値を参照できていることが分かります。

{
    "ContactFlowModuleType": "SetAttributes",
    "Parameters": {
        "Key": "valueObject1",
        "Value": "value1"
    }
}

{
    "ContactFlowModuleType": "SetAttributes",
    "Parameters": {
        "Key": "valueObject2",
        "Value": "value2"
    }
}

「プロンプトの再生」ブロック等で「$.External」記法を使って「外部」属性を参照する場合は、$.External.keyObject.subKey1のように記述します。

こちらも、コンタクトフローのログより、正しく値を参照できていることが確認できます。

{
    "ContactFlowModuleType": "PlayPrompt",
    "Parameters": {
        "TextToSpeechType": "text",
        "SpeakingStyle": "None",
        "Text": "1番目の値は value1 です。\n2番目の値は value2 です。",
        "Voice": "Kazuha",
        "GlobalEngine": "Neural"
    }
}

もちろん、実際に「value1」「value2」とプロンプト再生されます。

配列の場合

最後に、配列をデータ構造に持つJSONを戻り値に設定してみます。

export const handler = async(event) => {
    const response = {
        "keyArray": [
            "value1",
            "value2"
        ]
    };
    return response;
};

この場合ですが、「コンタクト属性の設定」「プロンプトの再生」の各ブロックで「外部」属性を参照する記述方法をいくつか試しましたが、いずれも値を参照することはできませんでした。

  • keyArray.0あるいは$.External.keyArray.0
  • keyArray.1あるいは$.External.keyArray.1
  • keyArray[0]あるいは$.External.keyArray[0]
  • keyArray[1]あるいは$.External.keyArray[1]

他に思いつく方法が無かったので、配列をデータ構造を持つJSON形式の戻り値を参照するのは諦めました。

検証結果

今回の検証結果をまとめると、以下のようになります。

  • コンタクトフローからLambda関数に対してパラメーターを与える時
    • 一般的なJSONの記法で問題ない
    • データ型は「数値型」「文字列型」「ブール型」「Null型」に加えて、オブジェクト型や配列も記述できる
    • 「$.」記法を使ってコンタクト属性の値をJSONに含めることも可能
  • Lambda関数からの戻り値をコンタクトフローで参照する時
    • データ型は「数値型」「文字列型」および「オブジェクト型」であれば参照できる
    • 「ブール型」「Null型」および配列は参照できない

戻り値の「配列」については、もしかすると参照する方法があるのかもしれませんが、AWS公式ドキュメントには説明している箇所が見当たらず、現時点では不明です。

おわりに

今回の「What's new」の説明では "For example, you can now build self-service experiences to help customers track their order status based on multiple purchases in the last month rather than the single most recent purchase." (日本語に訳すと「例えば、『最近の1回の購入』ではなく『先月の複数回の購入履歴』から顧客が注文状況を追跡できるように、セルフサービス体験を構築できます」) となっていました。

これを読んで、コンタクトフローから都度Lambda関数を呼び出さなくても構造化された (あるいはリスト化された) データのやり取りを行えるようになることを期待していました。

しかし、検証した限りでは、パラメーターや戻り値でJSON形式を指定できても、上手く活用できる場面は限定的 (ほぼ無い) ではないかと思いました。

理由は、構造化・リスト化されたデータをコンタクトフローで扱う方法が仕組みとして提供されていないためです。

例えば、構造化されたデータの要素にアクセスする際に、サブキーを動的に変数 (コンタクト属性) で与えて指定したり、「for each」 的な処理を行うといったことができません。
Lambda関数が戻り値を「オブジェクト型」を含むJSON形式で返しても、コンタクトフローから参照する際には構造が固定化されたデータとして扱うしかなく、これだとせいぜい「意味的にまとまりのある値をグループ化する」程度の効果しか期待できません。

また、コンタクトフローには「ループ」ブロックが用意されていますが、ループ内で現在の繰り返し回数を取得する手段はありません。
そもそも「配列」を含むJSON形式をコンタクトフローから参照する方法が無い (分からない) ので議論する余地も無いのですが、仮に可能だったとしても「配列として返されたデータを1件ずつ取り出して読み上げる」等の処理を行うことはできないのではないかと思います。

結論としては、現時点ではLambda関数の「入力パラメーター」と「出力レスポンス」をJSON形式でやり取りする必要性は薄いと考えますが、将来的にコンタクトフローの仕組みを含めて機能が拡張されることを期待したいと思います。