requestAttributesのちゃんとした使い方をre:Inventで知った。#Alexadevs #reinvent
せーのでございます。
今日はre:Inventでたまたま行ったチョークトークにてたまたま知ったAttributesの使い方を共有します。
Attributesは三種類
突然ですが皆さんはAlexa SDKのAttributes、ちゃんと使えてますか?
SDKに用意されているAttributesは
- Request Attributes
- Session Attributes
- Persistent Attributes
の三種類です。
それぞれ見ていきましょう。
Request Attributes
1リクエスト、つまり1回きりのやりとりでのみ有効になる値を保持しておくものです。
Session Attributes
1セッション、つまり1回の会話のやりとりの間保持される値を入れておきます。 Alexaサーバー内メモリに一時的に保持されます。
Persistent Attributes
永続化、つまりセッションが終わっても値を保持し続けます。 DynamoDBをつなぎ、Alexaの外に値を出すことで永続化されます。
会話のやりとり内で必要なものはSession Attributesに、次回以降のアクセスでも覚えておきたいものはPersistent Attributesに、と使い分ける事が重要です。人間が2回目以降にあった人に、前回の会話でのコンテキストを元に話すのと同じですね。
Request Attributesっている?
ここでひとつ疑問がでてきます。Sessionの概念はWebなどでもよく使うのでわかります。Persistentも要はずっと使う情報(生年月日や好み、アレルギーなど)に使うんだろうな、ということが想像できます。
では、Request Attributesとは、一体何に使うのでしょう?「1回のやりとりで保持する値」というのはLambdaであればほぼすべての変数がそれに当たります。わざわざRequest Attributesに入れなくても引数で関数に渡したり、もっと言えばグローバル変数に入れておいても同じことができるはずです。
そこで、ドキュメントを読んでみます。
アトリビュートのスコープ
リクエストアトリビュート
リクエストアトリビュートは、1回のリクエスト処理ライフサイクルの間のみ存続します。リクエストを受信した時点では、リクエストアトリビュートは空です。また応答が生成されると破棄されます。リクエストアトリビュートは、リクエストと応答のインターセプターと合わせて使うと便利です。たとえば、リクエストインターセプターを使って追加のデータとヘルパークラスをリクエストアトリビュートに挿入して、リクエストハンドラーから取得できるようにすることが可能です。
インターセプターに追加のデータとヘルパークラスを挿入、、、なるほど、わかりません。
では一つづつ噛み砕いてみましょう。
インターセプター
インターセプターとは、メインのリクエスト / レスポンスメソッドが始まる前後に通すことができるメソッドです。スキルを通じて共通で行うべき処理を書くのに向いています。
例えばレスポンスのインターセプター(ResponseInterceptor)の中に先程出てきたPersistentAttributesへのSaveメソッドを書きます。そうすることで「データの永続化処理」というシステム的な動きとビジネスロジックが分離できるわけですね。
ヘルパークラス
ヘルパークラスとは、ある処理を行いたいときに、そのコードを一つのマニュアルとしてラップし、手順を簡素化するための関数のことです。
例えばDeviceAddressServiceというクラスは実際に書くと複雑な「住所情報を取得する」という処理を、この関数を叩くだけで行ってくれるヘルパークラスです。
つまり、インターセプターの中でリクエストの中から得ることのできるデータと、それを使うためのヘルパークラスを一緒にRequestAttributesの中に入れることで使いやすくする、ということらしいです。
では、何のデータと何のヘルパークラスが入るのでしょう。
答えはre:Inventの中に
そんな疑問を抱きながら日々の仕事に追われていたある日、ラスベガスにて参加したAWS最大のカンファレンス「re:Invent」にて突然その答えにめぐりあいました。私はAlexaのチョークトーク(登壇者と参加者がホワイトボードなどを使ってお互いにディスカッションを行うセッション)に参加していました。
このセッションは「Alexaに自然な受け答えをさせるには」というテーマでのディスカッションが行われていました。そこで出てきたテーマの一つが「ユーザーの話す言語に合わせる」というものです。これは日本のユーザーには日本語で、英語圏のユーザーには英語で、ドイツのユーザーにはドイツ語で、、、というように、そのスキルがどの国で作られたものがが気にならないようにしよう、というものです。いわゆる多言語対応ですね。
その実装方法でこのような話が出てきました。
言語のローカリゼーションを行う時は、localizationInterceptorというリクエストインターセプターを作って、そこでrequest attributesに言語ファイルと"t"関数をバインドするといい。言語ファイルからIDを振ることはできない。
突然でてきましたが、Alexaには言語ファイル(Language String File)というものが作れます。
これをi18n(国際化)用のフォルダに突っ込み、インターセプターでロケールごとに選択してlocalization clientのt関数をrequest Attributesにバインドさせる形をとるわけです。なるほど、これならわかります。 これなら、ロケールが変わった時にも即座に対応できますし、Lambda特有の「たまたま同じサーバー使ってる時はなんか変数が残っちゃってる問題」もクリアできます。
つまり、request attributesとは、毎リクエストごとに変わる可能性のあるパラメータを元に、何かしらのクラスの初期設定をし、それを元に関数を使用する場合にバインドさせて、そのクラスを模倣するために使う、のですね。
ちなみにi18n、というのはinternationalization、と書くのが長いのでiとnの間に18文字あります、という略語です。
まとめ
いかがでしたでしょうか。長年ふわっとしていたrequest Attributesの使い方の片鱗が理解できました。これだけでも、re:Invent行ってよかったです。
ちなみに同じロケールでも違う言語を当てはめることもできます。こちらの詳細は下のリンクを参考にしてくださいね。