Lambda環境を利用してPieceをつくる

目次

Lambda上で動作するコードさえ実装すれば、スマートフォン上のネイティブコードの動きやRiiiver SDKの動作について理解しなくても、S/A Pieceを作成することが可能です。実際の動作としてはRiiiver SDKPieceCoreが連携してLambda上の関数を呼ぶのですが、 下の図の様な動作を一切意識する必要はありません。

以下の図のようにRiiiver SDKやスマートフォン側の実装をブラックボックスとして扱い、Lambda上で稼働するプログラムの開発だけに集中できます。

今回は Node.js を使って開発をした場合を例に説明をします。
上の図のように開発を進めるには、まずPieceJSONのキーを以下のように定義します。

"blockType":"service", //← A Pieceを作りたい場合は"action"
"executor":"RBCCommonWebServiceExecutor", //← SDKにビルトインされているPieceCore。これを指定。
"serviceProxy":{
  "service":"citizenSample" //← 皆さまがつくるLambda上のJavascriptファイル名から.jsを抜いたもの
},

PieceJSONに上記キーを含めれば、あとはLambda上に皆さまがアップロードしたJavascriptファイルが呼ばれた後からの動作を考えるだけです。

RiiiverではPieceBuilderというWebツールを準備しています。PieceBuilderはファイルアップローダーのような役割を果たし、PieceBuilderを利用することで、皆さまが作成したPieceのプログラムファイルをLambda上に適切に設置することができます。RiiiverLambda環境は、他の開発者の皆さまと共有して利用することができます。

皆さまが開発したLambdaで動作するPieceを含んだiiideaをユーザーが実行した場合、PieceJSON"serviceProxy"内の"service"で定義したファイル名のスクリプトを実行します。

実際のJavascriptは、通常のLambdaのものと同じく以下のようなコードです。

'use strict';
exports.handler = async event => {

  var response = {
    status: 200,
    body: {
      resultOfThisPiece:0.0   // Initialization
    }
  };

  //....ここに処理....

  //....結果を返却....
  return response;
};

皆さまが作成したPieceの実行順になったら、このハンドラが呼ばれます。このハンドラから抜ける時、戻り値にresponse変数に定義しているようなJSONデータを格納して返却する必要があります。response内のbody:で定義している{...}で囲まれている内容が、次のPieceに渡されるデータとなります。例えば、上に示すコードをそのままPieceとしてアップロードした場合、このPieceの出力は{ 0.0 }です。


ローカル環境でデバッグする環境を整える

皆さまの作成したコードをRiiiverLambda環境にアップロードしていただく前に、ローカル環境でデバッグしながら開発を進める方法をご紹介します。

準備

デバッグには以下のツールを利用してご説明しますので、各自の開発環境にインストールをお願いします(現状、他の環境では動作確認できておりませんので、ここでは環境を揃えさせていただければ幸いです)。

サンプルコードの中では、天気を取得するREST-APIを提供しているOpenWeatherというサービスを利用します。APIを利用して天気情報を取得するために、APIの利用登録を行ってください。

1. OpenWeather Webページからアカウント作成画面に進む。

2. 必要な入力事項を登録してアカウント作成。

3. 登録したメールアドレスに以下のようなメールが届きます。

このメールで言うところのYour API Key is 98d2......cとなっている文字列がAPIを利用するときに必要なキーです。メモなどを取っておいてください。

4. 動作を確認します。

メール中のExample of API call: api.openweathermap.org/.....は実際に入手したキーでAPIをコールする例です。ここではロンドンの現在の天気情報を取得する例になっています。このURLをそのままクリックしてみましょう。以下のようなページが表示されれば問題ありません。

それでは実際にローカル環境で動作を確認してみましょう。サンプルコードをダウンロードして下さい。


サンプルコードを展開する

サンプルコードの構成

サンプルコードを解凍すると以下のような構成になっています。

Sample Code
├── .vscode
├── kicker_on_lambda.js
└── YourCode
    ├── JSON
    │   └── pieceJson_Sample.json ✏️
    ├── ProxyCore
    │   └── pieceCore_Sample.js ✏️
    └── event.json ✏️

✏️これは開発時に皆さまで編集が必要なファイルになりますので、移動はしないでください。

  • SampleCode サンプルプロジェクトのルートフォルダ。
    • .vscode VS Codeの設定ファイル。
    • kicker_on_lambda.js RiiiverLambda環境のトリガーを模擬するキッカー。
    • YourCode 皆さまのコードを格納するフォルダ。
  • JSON 皆さまが作成するPieceJSONを格納するフォルダ。
    • pieceJS_Sample.json 皆さまが記述するPieceJSON。ファイル名は自由。拡張子は.json
  • ProxyCore 皆さまのPieceCoreを格納するフォルダ。
    • pieceCore_Sample.js PieceCoreの本体。ファイル名は自由ですが、PieceJSONで指定したファイル名と一致する必要があります。
  • event.json PieceCoreに渡すデータ。前のPieceからの出力と、ユーザーの設定情報などをこのファイルで模擬します。
Local環境での動作を理解する

サンプルコードはそのまま実行することができます。実際にローカル環境で実行して動きを確認してみましょう。Pieceが動作する際、Lambda上で実行されるタイミングを理解するのが重要です。ローカル環境でも本番のLambda環境と近い動作をするように構成しています。Lambdaの代わりに、皆さまのコードを実行してくれるのが、kicker_on_lambda.js です。中身まで読む必要はありませんが、このJavascriptをコールすることで、前のPieceから皆さまのPieceの順番になったときの動作をエミュレートします。

SampleCode
├── .vscode
├── kicker_on_lambda.js  ← これがLambdaをスタートさせたときと同じ動作をエミュレートします。 
└── YourCode
    ├── JSON
    ....

一度、実際に動作させてみましょう。

API Keyの設定

実行するためには、皆さまが取得したAPI Keyを設定する必要があります。サンプルフォルダをVS Codeで開いてみましょう。

SampleCode」フォルダを開いてください。

フォルダの階層を間違わないようにお気をつけください。
開くフォルダを間違うと、デバッグできません。

SampleCode/YourCode/ProxyCore/pieceCore_sample.js をクリックして開きます。apikey変数に、先ほど取得した皆さまのOpenWeatherAPI Keyを入力してください。Keyの文字列を""で囲み、書き換えたら上書き保存をします。

必要なnode modulesのインストール

このサンプルではHTTP通信でWeb上のAPIに接続します。HTTPの通信部分の実装を簡単にするために、このサンプルではrequestというモジュールを利用します。以下のコマンドを実行してrequestのモジュールをインストールしましょう。

1. サンプルコード(Javascript)がある位置まで移動します。

# For Windows
cd (place you extract the sample folder)\SampleCode\YourCode
# For Linux/Mac
cd (place you extract the sample folder)/SampleCode/YourCode

2. npmコマンドを実行して必要なモジュールをインストールします。

npm install request

3. node_modules」フォルダ内に必要なライブラリがインストールされます

これで通信用モジュールを使うための準備が整いました。

ターミナルで実行する

では実行してみましょう。Linux/Macの場合はターミナル、Windowの場合はコマンドプロンプトを開いて「SampleCode」ディレクトリまで移動します。

# For Windows
cd (place you extract the sample folder)\SampleCode
# For Linux/Mac
cd (place you extract the sample folder)/SampleCode

そして以下のコマンドを入力して実行します。

# For Windows
node .\PieceDebugger\kicker_on_lambda.js
# For Linux/Mac 
node ./PieceDebugger/kicker_on_lambda.js

次のような結果が出るはずです。

Proxy経由で接続する環境で実行する場合は注意してください。
正しく動作しない可能性があります。
$ node ./PieceDebugger/kicker_on_lambda.js 
start: event = {"serviceProxy":"citizenSample","properties":{"preferences":{"cityName":"Tokyo"},"parameters":{},"input":{}}}
https://api.openweathermap.org/data/2.5/weather?q=Tokyo,jp&APPID=98d2xxxxxxxxxxxxxxxxxxxxxxxxc
getWeatherInfo: start
getWeatherInfo: response = {"statusCode":200,"body":"{\"coord\":{\"lon\":139.76,\"lat\":35.68},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"base\":\"stations\",\"main\":{\"temp\":297.19,\"pressure\":1006,\"humidity\":69,\"temp_min\":293.71,\"temp_max\":299.26},\"visibility\":10000,\"wind\":{\"speed\":7.2,\"deg\":240},\"clouds\":{\"all\":75},\"dt\":1570525660,\"sys\":{\"type\":1,\"id\":8074,\"message\":0.0078,\"country\":\"JP\",\"sunrise\":1570480841,\"sunset\":1570522589},\"timezone\":32400,\"id\":1850147,\"name\":\"Tokyo\",\"cod\":200}","headers":{"server":"openresty","date":"Tue, 08 Oct 2019 09:12:31 GMT","content-type":"application/json; charset=utf-8","content-length":"466","connection":"close","x-cache-key":"/data/2.5/weather?APPID=98d2xxxxxxxxxxxxxxxxxxxxxxxxc&q=tokyo,jp","access-control-allow-origin":"*","access-control-allow-credentials":"true","access-control-allow-methods":"GET, POST"},"request":{"uri":{"protocol":"https:","slashes":true,"auth":null,"host":"api.openweathermap.org","port":443,"hostname":"api.openweathermap.org","hash":null,"search":"?q=Tokyo,jp&APPID=98d2xxxxxxxxxxxxxxxxxxxxxxxxc","query":"q=Tokyo,jp&APPID=98d2xxxxxxxxxxxxxxxxxxxxxxxxc","pathname":"/data/2.5/weather","path":"/data/2.5/weather?q=Tokyo,jp&APPID=98d2xxxxxxxxxxxxxxxxxxxxxxxxc","href":"https://api.openweathermap.org/data/2.5/weather?q=Tokyo,jp&APPID=98d2xxxxxxxxxxxxxxxxxxxxxxxxc"},"method":"GET","headers":{}}}
output:  {"status":200,"body":{"celsiusTemperature":24.04000000000002}}

Your Function Output ::  {"status":200,"body":{"celsiusTemperature":24.04000000000002}}

いろいろなログが出ていますが、このサンプルPieceが次のPieceに出力するデータは最終行の"body"キー内の

{"celsiusTemperature":24.04000000000002}}

です。実際のファイルを見ながら動作の流れとPieceCoreの記述方法についてこの後に確認していきます。

Debugしてみる

先ほどはターミナル/コマンドプロンプトで実行しましたが、VS Codeを利用すると、ブレークポイントなどを仕掛けて動作をデバッグすることができます。デバッグできると実装効率があがりますので、ぜひ利用しましょう。

Debug環境設定

API Keyの設定のときと同じく、プロジェクトフォルダ「SampleCodeName」をVS Codeで開いてください。VS Codeの左側のアイコンが並ぶペインでデバッグのボタン(虫のアイコン)をクリックします。

これでデバッグ画面になります。次にデバッグ時に実行するファイルなどを設定します。↓の図の歯車のボタンをクリックして下さい。

すると、上記のように launch.jsonVS Codeのデバッグ環境設定ファイル)の編集画面になります。ここで"program":で記述されている内容を変更します。上図のように kicker_on_lambda.js を実行するように設定してください。

"program": "${workspaceFolder}/PieceDebugger/kicker_on_lambda.js"

Node.js のデバッグ機能はVS Codeに標準で組み込まれていますので、特に拡張機能のインストールなども必要ありません。kicker_on_lambda.js は名前の通り、AWSLambdaの代わりに皆さまが実装したコードをPieceJSONに記述している通りに呼び出すものです。

以上でデバッグの為の準備は整いました。実際にデバッグしてみましょう。

VS Code上でブレークポイントなども仕掛けられます。最初に正しくデバッグ環境が設定されて、kicker_on_lambda.jsが無事に実行されているか確認するために、このファイル内にブレークポイントを設定してみましょう。

  1. 画面左のアイコンでファイルをクリックして、プロジェクトフォルダ内を表示します。
  2. kicker_on_lambda.jsファイルをクリックして、ソースを表示します。
  3. kicker_on_lambda.jsのタブを選択します。(選択されていない場合)
  4. 9行目の行番号の左側の部分をクリックして、赤丸(ブレークポイント)をつけます。

これで、正しく動作すれば、kicker_on_lambda.jsが実行され、9行目に到達したときに一時停止するはずです。

Debug動作確認

実際にデバッグ実行してみましょう。

  1. もう一度虫のアイコンをクリックしてデバッグモードにします。
  2. ↓の再生マーク実行すると、デバックが開始されます。

正しく動作したら、↓のように9行目に設定したブレークポイントで一時停止されるはずです。

ブレーク時のローカル変数、グローバル変数は「VARIABLES」のペインで確認できます。またマウスカーソルをソースコード上の変数などでマウスオーバーすると、ブレイク時の値や状態を確認することができます。

そのまま実行する場合には、下のボタンをクリックしましょう。

サンプルコードが正しく動作すれば、VS Codeの「DEBUG CONSOLE」に以下のようにconsole.log()の出力が確認できると思います。

上の画面のように、ターミナルで実行した時と同じ様に結果を出力していることがわかるかと思います。

{"status":200,"body":{"celsiusTemperature":23.52000000000004}}

PieceJSONを準備する

Pieceの仕様書となるPieceJSONを準備します。すでに動作するものがサンプルプロジェクトに含まれています。YourCode/JSON/pieceJson_Sample.json がそうです(以下にも示しますが、今まで説明に利用してきたものと同じものです)
PieceJSONのファイル名は自由に変更できます(拡張子は.jsonとしてください)。
必要な記述事項について説明します。

{
  "title": {
    "en": "Current Temperature (celsius)",
    "ja": "現在の気温 (摂氏)"
  },
  "version": "1.0.0",
  "sdkVersion": "1.0.0",
  "deviceId": "none",
  "vendorId": "none",
  "description": {
    "en": "Current temperature in the setting area",
    "ja": "指定した地域の現在の気温を取得します。うまく取得できなかった場合は値が -50 となります。"
  },
  "blockType": "service",
  "executor": "RBCCommonWebServiceExecutor",
  "serviceProxy" : {
    "service": "pieceCore_Sample"
  },
  "preferences": {
    "type": "object",
    "properties": {
      "cityName": {
        "type": "string",
        "enum": [
          "Sapporo-shi",
          "Tokyo",
          "Osaka",
          "Fukuoka-ken",
          "Okinawa-ken"
        ],
        "default": "Tokyo",
        "x-input-type": "drumroll",
        "x-title": {
          "ja": "地域",
          "en": "Area setting"
        },
        "x-description": {
          "en": "set the area from which to get the temperature.",
          "ja": "気温を取得する地域を指定します。"
        },
        "x-enum-titles": {
          "Sapporo-shi": {
            "ja": "札幌市",
            "en": "Sapporo"
          },
          "Tokyo": {
            "ja": "東京都",
            "en": "Tokyo"
          },
          "Osaka": {
            "ja": "大阪府",
            "en": "Osaka"
          },
          "Fukuoka-ken": {
            "ja": "福岡県",
            "en": "Fukuoka"
          },
          "Okinawa-ken": {
            "ja": "沖縄県",
            "en": "Okinawa"
          }
        }
      }
    }
  },
  "output": {
    "type": "object",
    "properties": {
      "celsiusTemperature": {
        "type": "number",
        "minimum": -50,
        "maximum":  50
      }
    }
  },
  "osType":"none",
  "categoryIds": ["cat_0007"]
}

繰り返しますが、ここで重要なのが"executor""serviceProxy"です。

"executor": "RBCCommonWebServiceExecutor",
"serviceProxy" : {
    "service": "pieceCore_Sample"
},

"executor"の値は、Riiiverが準備したLambda環境で動作するプログラムを作るときには必ず"RBCCommonWebServiceExecutor"になります。"serviceProxy"内の"service"で指定する値は、皆さまが記述するロジック部分に当たるJavascriptのファイル名から.jsを除いたもの指定してください。
上の例では pieceCore_Sample.js ファイルのhandlerLambdaからコールされます(.jsファイルについては、この後触れます)


Preferenceについて理解する

この例で重要になるのが"preferences":以下で囲まれている情報です。

Preferenceは皆さまが作ったPieceiiideaの一部として実行される前に、エンドユーザーにセットしてほしい設定項目を定義します。ユーザーはiPhone/Android端末から設定することになります。この pieceJson_Sample.json preferenceはユーザーには以下のようなUIが表示されます。

preference内のJSONを読み込んでみましょう。まず、"type":ですが、これは常に"Object"とします。"properties"で指定するキーが、ユーザーに設定してもらう値の名前になります。この例だと、"cityName"です。続いて"cityName"について定義が続きます。"cityName"の方は"string"です。取り得る値はenumで定義していますので、下記値のどれかが"string"として設定されます。

[
  "Sapporo-shi",
  "Tokyo",
  "Osaka",
  "Fukuoka-ken",
  "Okinawa-ken"
],

ユーザーがこの値を設定しない場合は、"default"の値が設定された状態でPieceが動作します。この例では"default":"Tokyo",ですので"Tokyo"が設定されます。
他の"x-"から始まるキーはUIの指定に関するものです。次に主要なUIに関するキーの説明をします。

x-input-type

ユーザーに表示するUIの種類をここで指定することができます。以下のUIをユーザーに表示して、必要な情報を設定してもらうことができます。

  • time
  • switch
  • map
  • radio
  • date
  • slider
  • textarea
  • text
  • drumroll

今回の例では「drumroll(ドラムロール)」を利用しています。

"x-input-type": "drumroll",
x-title

ユーザーに設定してもらう内容を簡単に表すようなタイトルを付けましょう。上のUI画面でいう「地域」が相当します。多言語対応です。

"x-title": {
  "ja": "地域",
  "en": "Area setting"
},
x-description

簡単な説明書きです。上のUI画面の「気温を取得する地域を指定します。」の部分が相当します。多言語対応です。

"x-description": {
    "en": "Set the area from which to get the temperature.",
    "ja": "気温を取得する地域を指定します。"
},
x-enum-titles
"x-enum-titles": {
  "Sapporo-shi": {
    "ja": "札幌市",
    "en": "Sapporo"
  },
  "Tokyo": {
    "ja": "東京都",
    "en": "Tokyo"
  },
  "Osaka": {
    "ja": "大阪府",
    "en": "Osaka"
  },
  "Fukuoka-ken": {
    "ja": "福岡県",
    "en": "Fukuoka"
  },
  "Okinawa-ken": {
    "ja": "沖縄県",
    "en": "Okinawa"
  }
}

実際に設定する値と、ユーザーに出したい情報が別の場合は、このようにユーザーに見せる文字列と設定値を別々にすることができます(ユーザーが「札幌市」を選択すると、"Sapporo-shi"が設定値となります)。
各値がenum値に対応していることがわかると思います。今回はSapporo-shiなどの都市名(ID)OpenWeather側の仕様で決まっています。これをユーザーにわかりやすく設定してもらうために、ドラムロールでは実際の地域名を漢字で表示させています。


実際にPreference画面を表示させて値を設定する

このようにPieceJSON内に記述することでユーザーに情報を設定してもらう画面を表示することができます。実際に記述しているJSONで問題なく表示できるのか、所望の設定値が設定されているのかを確認するため、オンラインツールのPieceJSON Generatorを準備しています。
PieceJSON Generatorを利用してPieceJSONのフォーマットが正しいか、Preferenceとして表示したいUIは期待通りか、実際に表示して確認することができます。

PieceJSON Generatorを利用する

実際に自分で記述したJSONファイルで正しくUIが生成できるか確認してみましょう。
https://piece-debugger.herokuapp.com/を訪れてください(現在のアドレス・機能は開発中の仮のものです)。以下のような画面が表示されると思います。

サンプルコードに含まれている先ほどのPieceJSONファイルの中身をコピーアンドペースト、もしくはFile > Openからファイルを指定して開いてください。以下の様な画面になるはずです。

PieceJSONのフォーマットをチェックする

現在記載されているPieceJSONのフォーマットが正しいか、必須となっているキーがは全て記述されているかを確認をするには、「Debug」メニューの「Check Piece Format」をクリックします。

すると、画面下のペインに結果が表示されます。

ここでエラーが出た場合には、エラーメッセージを確認して修正作業に入りましょう。

Preference UIを確認する

PieceJSONPreference設定項目を記述している場合には、PieceDebuggerを利用してユーザーに設定してもらいたい画面を実際に表示して確認することができます。
メニューの「Preview」をクリックし、英語で画面を確認するか、日本語で画面を確認するか選択します。

上の例では英語でのUI表示を確認しています。Englishを設定した場合、PieceDebuggerの右のペインに結果が表示されます。

今回の例ではServcie Pieceを作成しているので、S Serviceのセクションに皆さまが記述したUIが表示されます(Piece単体の確認をするためにPieceDebuggerを利用しますが、実際にユーザーがPreference画面を見る場合はiiideaの詳細画面になります。そのため、右のペインでもiiideaの設定画面を表示しています。ただし、PieceDebuggerでは現在確認しているPiece以外の表示はなく、iiideaのタイトルもダミーです)。

右のペインはユーザーが操作する様に、実際に値を設定することができます。上記の例の様に、地域のドラムロールUIをクリックして「Osaka」を選択してみましょう。選択が終わったらメニューの「Debug」ボタンをクリックし、続いて「Check Preference」をクリックしてください。

画面下のペインのデバッグコンソール部分に表示された下記の

preferences: {"cityName":"Osaka"}

が実際に皆さまのPieceの順番になった時に渡ってくるユーザーが設定した値になります。
この値をユーザが設定した値とみた立てて、デバッグすることができます。


Input/Outputについて理解する

PieceJSONではPieceが受け取ることができるデータの型と、次のPieceに出力するデータの型を定義します。
ユーザーがiiideaを作成する時、一つPieceを選択するとその前後に接続できるPieceかどうかはこのPieceJSON "input""output"の値で判断します。型が異なるPiece通しは接続することができないので、ユーザーには表示しない様な仕組みになっています。

input

サンプルのpieceJson_Sample.jsonファイルにはinputキーがありません。これはPieceが入力を受けないこと意味します。入力を受け付ける場合は以下の様に記述します。(↓の例では文字列を受け付ける)

"input": {
  "type": "object",
  "properties": {
    "inputstring": {
    "type": "string",
      "format" : "text",
      "x-title": {
        "en": "Inpurt Text",
        "ja": "入力されるテキスト"  
      },
      "x-description": {
        "en": "This Piece can receive the text such as ......",
        "ja": "このPieceは次の様なテキストを受け取れます: ○○○○○…"
      },
    }
  }
},
output

サンプルのpieceJson_Sample.jsonでは以下の様に定義されています。

"output": {
    "type": "object",
    "properties": {
        "celsiusTemperature": {
            "type": "number",
            "x-title" : {
                "en" : "Temperature (celsius)",
                "ja" : "気温(摂氏)"
            },
            "x-description" : {
                "en" : "Output the setting area's temperature in celsius.",
                "ja" : "指定した都市の温度を摂氏で出力します。"
            },
            "minimum" : -50,
            "maximum" : 50 
        }
    }
},

このPiece"celsiusTemperature"というキーで数字を出力することがわかります。


実行時のデータの流れを理解する

PieceJSONについては大まかにご説明しました。PieceJSONの詳細な情報はこちらのページを参照下さい。次に、実際にPieceが実行される時にどのようなデータが流れるのかを見ていきましょう。

Pieceに渡るデータ event.json

Pieceに渡るデータには上で説明したPreference設定を含め、以下のような値があります。

  • Preference
  • Input
  • Parameter
  • userData
Preference

上の例で示したpreferences: {"cityName":"Tokyo"}に相当する設定データです。ユーザーがさまざまなUIを介して設定することができます。他にどのようなUIがあるかはこちらのページをご参照ください。

Input

前のPieceの出力値です。

Parameters

前のPieceの出力値とは別に、スマートフォンの情報を取得することができます。現時点ではスマートフォンの現在位置情報の座標を取得できます。

userData

ユーザーのスマートフォン上での設定項目がuserDataとして渡されます。
userDataの中に以下の項目が含まれています。

  • date - ユーザーのスマートフォンのローカルタイムを取得できます。
  • languageCode - ユーザーがスマートフォンで利用している言語が取得できます。
  • countryCode - ユーザーがスマートフォンに設定している国を取得できます。

これらの情報を利用して、ユーザーの環境を考慮した動作をすることができます。
Pieceに入力される情報=Lambda実行時に渡ってくる情報」は以下のようなまとまったJSON形式のデータになります。

{
    "serviceProxy": "pieceCore_Sample",
    "properties": {
        "preferences": {
            "cityName": "Tokyo"
        },
        "parameters": {},
        "input": {}
    },
    "userData": {
        "date": "2020-03-27T13:09:18+0900",
        "languageCode": "ja",
        "countryCode": "JP"
    }
}

上記Pieceに渡るデータをLocal環境ではYourCode/event.jsonとして記述し、実際に動作させてデバッグします。

SampleCode
├── .vscode
├── kicker_on_lambda.js
└── YourCode
    ├── JSON
    │   └── pieceJson_Sample.json ✏️
    ├── ProxyCore
    │   └── pieceCore_Sample.js ✏️
    └── event.json ✏️   ←これ!!!

PreferenceエミュレータでUIで設定した値は画面右上のデバッグボタンを押すと、上記YourCode/event.jsonファイル内のpreferencesキーが書き換えられます。
ターミナルやコマンドプロンプトで実行したkicker_on_lambda.jsも上記event.jsonファイルで定義されたデータを入力ファイルとして読み込む仕組みになっています。

ブレークポイントを仕掛けてデバッグしてみる

それでは、実際のPieceevent.jsonファイルで設定したファイルが渡ってきている内容を確認してみましょう。またVS Codeを利用して、好きなところにブレークポイントを仕掛けます。

Lambdaが実行された直後動作

実際にAWS上のLambdaで皆さまのコードが実行される時を想定してexports.handlerで示す関数が呼ばれた直後にブレークポイントを仕掛けてみましょう。サンプルコードではpieceCore_Sample.jsファイルがexports.handlerを定義しています。

exports.handler = async event => {
  /* 
     Code for "warm start"
    The Riiiver system might call your Lambda function constantly to make it Warm Start.
    When the system called your function, the heavy modules are cached on the Lamba environment.
    The following code makes the (heavy) external module cached.
     ピースの実行速度高速化処理
    Lambda関数をウォームスタート状態にするために、このLambda関数は
    定期的にRiiiver System側からコールされることがあります。その際の処理をここで記述します。
    外部モジュールなどの重いインスタンスをキャッシュさせ、高速化します。*/
  if (event.call === 'lambda') {
    console.log('CALLED:LAMBDA');

    /* If you use the external modules, please code the following: - 外部モジュールを使う場合に記入してくだい。
       e.g.  if ( xxxx !== null ){} // xxxx: instance for the module.  -  xxxx : 生成したインスタンス */
    if (request !== null) { }

    return;
  }
  ...
11行目(サンプルコードでは17行目) if は絶対に消さずにそのままご使用ください。
通常、ここは通りませんが、別の役割がありますので、消さないでください。(詳細は後で説明します。)

ちょうど、29行目にコンソールにログを吐く様に仕掛けていますので、ここでブレークポイントを貼ってみましょう。

ここでもう一度デバッグ・実行ボタンを押して実行してみましょう。この時、Pieceに渡されている情報はevent変数として渡っています。eventの中を確認してみましょう。画面左のペインに「WATCH」というセクションがあります。ここの右側の「+」ボタンを押してeventと入力してみましょう。

するとevent変数の中身を表示することができます(実際はeventの中身は event.json で記入しているJSONオブジェクトです)。

preferencesとして{cityName: "Tokyo"}が渡っているのが分かると思います。
ブレークポイントを31行目に設定して、29行目のconsole.logを出力すると実際のeventの内容の出力が確認できます。以下のようになるはずです。

start: event = {"serviceProxy":"pieceCore_Sample","properties":{"preferences":{"cityName":"Tokyo"},"parameters":{},"input":{}},"userData":{"date":"2020-03-27T13:09:18+0900","languageCode":"ja","countryCode":"JP"}}

Pieceに入力・設定されたデータはeventとして渡されます。この変数をうまく利用して、処理していきましょう。


実行して実行結果を次のPieceに送る

実行時の処理

サンプルコードの処理を再度確認してみましょう。Lambda上で処理を行う対象のコードはPieceJSONで指定している通り、pieceCore_Sample.js です。要点となる部分をご説明します。

exports.handler = async event => {
  /* 
     Code for "warm start"
    The Riiiver system might call your Lambda function constantly to make it Warm Start.
    When the system called your function, the heavy modules are cached on the Lamba environment.
    The following code makes the (heavy) external module cached.
     ピースの実行速度高速化処理
    Lambda関数をウォームスタート状態にするために、このLambda関数は
    定期的にRiiiver System側からコールされることがあります。その際の処理をここで記述します。
    外部モジュールなどの重いインスタンスをキャッシュさせ、高速化します。*/
  if (event.call === 'lambda') {
    console.log('CALLED:LAMBDA');

    /* If you use the external modules, please code the following: - 外部モジュールを使う場合に記入してくだい。
       e.g.  if ( xxxx !== null ){} // xxxx: instance for the module.  -  xxxx : 生成したインスタンス */
    if (request !== null) { }

    return;
  }
最初のif文の処理について

if (event.call === 'lambda') { で始まるブロックは、皆さまのLambda関数を素早く実行するためにRiiiver側で準備している仕掛けです。このコードは 絶対に消さずに、 このまま残しておいてください。
Lambda関数をウォームスタートするために必要なコードがここに記載されています。Riiiverのシステムは、皆さまの関数を定期的に呼び出す処理を行います。定期的な呼び出しの処理はユーザーが実行した呼び出しではなく、Lambda関数の応答速度を上げるためのものです。この例で使っているような外部モジュールは、初期化するだけでも時間がかかるものです。外部モジュールを利用する処理をこのif文ブロックに入れておくことで初期化が完了するまで待つことができます。
皆さまのLambda関数が呼ばれて実行されるこの関数はasyncキーワードがついています。つまりこの関数は非同期に別スレッドで動作することになります。if (request !== null)の条件式を判断するタイミングでは、グローバル変数requestと定義したrequestモジュールはまだ初期化されていないかもしれません。このif文を実行しようとすることでプログラムはrequestモジュールの初期化の完了を待ってから条件式の評価に移ります。実際はその後に何もしていないのですが、ここで大きなモジュールの初期化が完了することに注目してください。
この関数をRiiiverシステムが定期的に呼び出したときに外部モジュールのインスタンスを初期化された状態でメモリにキャッシュさせるのが目的です。
外部モジュールを利用する際には'use strict;の下にグローバル変数として宣言し、if (event.call === 'lambda') {ブロック内で宣言した変数を使用する処理を入れてください。皆さまの関数の応答速度が上がります。

ユーザーが入力した地域情報を取得

現在気温を取得する地域情報を、ユーザーに設定してもらう想定で作成しています。cityNameに入る値はOpenWeatherの仕様に準拠した値が入る様にPieceJSONを作成しています。event.json ファイルの情報がPieceの入力データとして処理されevent変数に入ります。ユーザーの設定情報を下記のようにアクセスして抽出しています。

const cityName = event.properties.preferences.cityName;     // Get the location information entered by the user - 自分のpieceのプリファレンスの値
天気情報を取得

天気情報を取得しているのは以下の処理です。

// Get weather information - 天気情報を取得
let weatherData = await getWeatherInfo(urlString);

http通信用に追加したnodeモジュールrequestを使用して通信を実現しています。アクセス先のURLOpenWeatherの仕様に準拠しています。
https://api.openweathermap.org/data/2.5/weather」にクエリとしてid=cityNameの値を追加して通信すると、cityNameで指定した地域の天気情報が取得できます。

function getWeatherInfo(urlString) {
  return new Promise(function (resolve) {
    console.log('getWeatherInfo: start');
    let options = {
      url: urlString,
      method: 'GET',
    };
    request(options, function (error, response, body) {
      if (!error && response.statusCode === 200) {
        console.log('getWeatherInfo: response = ', JSON.stringify(response));
        resolve(JSON.parse(response.body));
      } else {
        console.error('getWeatherInfo: response = ', JSON.stringify(response));
        resolve(null);
      }
    });
  });
}
次のPieceへ送るoutput情報を作る

取得した現在の気温を次のPieceへ送るためにoutput情報を作成します。

// 天気情報から今日の情報を取得 
if (weatherData) { 
  const tempK = weatherData.main.temp; // 得られたJSON内の温度を保存。単位はケルビン。
  response.body.celsiusTemperature = tempK - 273.15; // 次のブロックに返す値は摂氏で数値(Number) 
}

Lambdaの関数から戻り値を渡すときのフォーマットは常に下のようにHTTPの結果と次のPieceへのoutputのデータとなります。

{
  status:200,
  body:{
    celsiusTemperature:-1.0
  }
};

以上でサンプルコードに関する説明は終了です。

その他にもLambda上で実現できる機能がありますので、「Pieceの機能を拡張する」をご覧ください。また作成してデバッグしたPieceをアップロードする場合は「Pieceをアップロードする」をご覧ください。