Riiiverが準備するLambda環境を利用してS/A Pieceを作成する

In Piece

この文章では、スマホ上のネイティブコードの動きやSDKの動作について理解しなくてもPieceを作成できる方法を紹介します。Lambda上で動作するコードさえ実装すればS/A Pieceを作ることができます。実際の動作としてはSDKとPieceCoreが連携してLambda上の関数を呼ぶのですが、 ↓

PieceCore and Lambda

上の図の様な動作は一切意識することなく、コーディングできる環境を準備しました。SDKやスマホ側をブラックボックスとして扱い、スマホ上の実装を意識せずにLambda上のJavascriptの開発だけに集中できます。

PieceCore and Lambda

上の図の様に開発を進めるには、PieceJSONのキーを以下の様に定義します。

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

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

RiiiverにはPieceBuilderというWebツールを準備しています。PieceBuilderはファイルアップローダーの様な役割を果たし、PieceBuilderを利用することでLambda上に適切にファイルを置くことができます。LambdaはRiiiverが準備しています。他の開発者さんと共有して利用しますので下図の様な感じになります。

PieceCore and Lambda

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

PieceCore and Lambda

実際の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 }です。

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

Riiiverが準備するLambdaに作成したコードをアップロードしたら動作するのですが、アップロードしないとデバッグできないとなると、開発が困難です。ここではローカル環境でデバッグしならが開発を進める方法を記します。

準備

デバッグには以下のツールを利用して説明しますのでインストールをお願いします。

(他の環境では動作確認できておりませんので、ここでは環境を揃えさせて下さい。)

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

  1. OpenWeather Webページからアカウント作成画面にいく。
    Sign Up

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

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

    このメールの- Your API Key is 98d2... ...cとなっているのがAPIを利用する時に必要なキーになります。ここをメモして下さい。

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

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

サンプルコード

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

サンプルコードの構成

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

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

​ ✏️ みなさんで編集するファイル。開発時に編集が必要なファイルです。移動はしないでください。

  • SampleCode – サンプルプロジェクトのルートフォルダ。
    • .vscode – VS Codeの設定ファイル。
    • kicker_on_lambda.js – Riiiverで準備したLambdaのトリガーを模擬するキッカー。
    • YourCode – みなさんのコードを格納するフォルダ
      • JSON – みなさんが作成するPieceJSONを格納するフォルダ。
        • pieceJson_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で開いてみましょう。

VS Codeでサンプルプロジェクトを開く

SampleCodeのフォルダを開いて下さい。(階層を間違わないように!)

VS Code PieceCoreのAPI Keyの編集

SampleCode/YourCode/ProxyCore/pieceCore_sample.jsをクリックして開いてみましょう。
apikey変数に取得したみなさんのAPI Keyを入力してください。Keyの文字列を””で囲む感じです。書き換えたら上書き保存しましょう。

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

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

  1. サンプルコード(Javascript)がある位置まで移動します。
    # Windowsの場合
    cd (サンプルコードを解凍した場所)\SapmleCode\YourCode\ProxyCore
    # Linux/Macの場合
    cd (サンプルコードを解凍した場所)/SapmleCode/YourCode/ProxyCore
    
  2. npmコマンドを実行して必要なモジュールをインストールします。
    npm install request
    
  3. node_modulesフォルダ内に必要なライブラリがインストールされます。

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

Terminalで実行する

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

 # Windowsの場合
 cd (サンプルコードを解凍した場所)\SapmleCode
 # Linux/Macの場合
 cd (サンプルコードを解凍した場所)/SapmleCode

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

# Windowsの場合
node kicker_on_lambda.js
# Linux/Macの場合 
node kicker_on_lambda.js

次のような結果が出るはずです。(Proxy越しに接続する環境で実行した場合などは正しく動作しないかもしれません。)

$ node kicker_on_lambda.js 
start: event = {"serviceProxy":"pieceCore_Sample","properties":{"preferences":{"cityName":"Tokyo"},"parameters":{},"input":{}}}
https://api.openweathermap.org/data/2.5/weather?q=Tokyo,jp&APPID=98d2xxxxxxxxxxxxxxxxxxxxxxxxc
getWeatherInfo: start
Promise { <pending> }
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":{}}}
{"status":200,"body":{"celsiusTemperature":24.04000000000002}}

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

{"celsiusTemperature":24.04000000000002}}

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

Debugしてみる

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

Debug環境設定

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

VS Code Debug1

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

VS Code Debug2

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

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

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

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

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

VS Code Debug3

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

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

Debug動作確認

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

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

VS Code Debug4

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

VS Code Debug5

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

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

VS Code Debug

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

VS Code Debug6

↑のようにTerminalで実行した時と同じ様に結果を出力していることがわかるかと思います。

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

Piece Jsonを準備する

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": "指定した地域の現在の気温を取得します。うまく取得できなかった場合は値が -1 となります。"
  },
  "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"
      }
    }
  },
  "osType":"none",
  "categoryIds": ["cat_0007"]
}

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

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

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

Preferenceについて理解する

この例で重要になるのが"preferences":以下で囲まれている情報です。
Preferenceはみなさんが作ったPieceがiiideaの一部として実行される前に、エンドユーザーにセットしてほしい設定項目を定義します。ユーザーはiPhone/Android端末から設定することになります。このpieceJson_Sample.jsonのpreferenceはユーザーには以下のようなUIが表示されます。

都市選択のPreference設定画面

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

上のUI画面の「札幌市、東京都、大阪府、福岡県、沖縄県」部分が相当します。

"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)はOpenWeatherMap側の仕様で決まっています。これをユーザーにわかりやすく設定してもらうためにドラムロールでは実際の地域名を漢字で表示させています。

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

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

Online PieceDebuggerを利用する

実際に自分で記述したJSONファイルで正しくUIが生成できるか確認してみましょう。

https://piece-debugger.herokuapp.com/ を訪れてください。(現在のアドレス・機能は開発中の仮のものです。)以下の様な画面が表示されると思います。

PreferenceDebugger Top

サンプルコードに含まれている先ほどのPieceJSONファイルをコピペ、もしくは開いてください。以下の様な画面になるはずです。

PreferenceDebugger Top

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

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

PreferenceDebugger Top

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

PreferenceDebugger Top

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

Preference UI を確認する

PieceJSONにPreference設定項目を記述している場合には、PieceDebuggerを利用してユーザーに設定してもらいたい画面を実際に表示して確認することができます。

メニューの「Preview」をクリックし、英語で画面を確認するか、日本語で画面を確認するか選択します。

PreferenceDebugger Top

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

PreferenceDebugger Top

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

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

PreferenceDebugger Top

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

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"
    }
  }
},

output

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

"output": {
  "type": "object",
  "properties": {
    "celsiusTemperature": {
      "type": "number"
    }
  }
},

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

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

PieceJSONについてはなんとなく理解ができたと思います。PieceJSONの詳細な情報はこのページを参照下さい。
次に、実際にPieceが実行される時にどの様なデータが流れるのかを見ていきましょう。

Pieceに渡るデータ – event.json

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

  • Preference
  • Input
  • Parameters

Preference

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

Input

前のPieceの出力値。

Parameters

前のPieceの出力値とは別に、スマホの情報をもらうことができます。
現在はスマホの現在位置情報の座標をもらうことができます。

これらPieceに入力される情報=Lambda実行時に渡ってくる情報は以下の様なまとまったjson形式のデータになります。

{
    "serviceProxy": "citizenSample",
    "properties": {
        "preferences": {
            "cityName": "Tokyo"
        },
        "parameters": {},
        "input": {}
    }
}

上記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ファイルで定義されたデータを入力ファイルとして読み込む仕組みになっています。

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

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

Lambdaが実行された直後動作

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

'use strict';
exports.handler = async event => {
  // 受け取った情報をログで出力しておく
  console.log('start: event = ' + JSON.stringify(event));

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

VS Code Debug8

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

VS Code Debug9

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

VS Code Debug10

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

start: event = {"serviceProxy":"citizenSample","properties":{"preferences":{"cityName":"Tokyo"},"parameters":{},"input":{}}}

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

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

実行時の処理

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

'use strict';
const request = require('request');
exports.handler = async event => {
  //lambda開始 
   if (event.call == "lambda") {
    console.log("CALLED:LAMBDA");
    return;
  }
  // 受け取った情報をログで出力しておく
  console.log('start: event = ' + JSON.stringify(event));

  const apiHost = "https://api.openweathermap.org";
  const apiPath = "/data/2.5/weather";
  const apikey = "98d2xxxxxxxxxxxxxxxxxxxxxxxxxc";    // ←ここに皆さんのAPI Keyを入れる
  let response = {
      status: 200,
      body: {
          celsiusTemperature: -1.0
      }
  };

  const cityName = event.properties.preferences.cityName;     // 自分のpieceのプリファレンスの値
  const urlString = `${apiHost}${apiPath}?q=${cityName},jp&APPID=${apikey}`;  //URLの文字列を完成させる。
  console.log(urlString);

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

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

  // output情報をログで出力しておく
  console.log(JSON.stringify(response));

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

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));
        // レスポンスのBodyを返却
        resolve(JSON.parse(response.body));
      } else {
        console.error('getWeatherInfo: responce = ' + JSON.stringify(response));
        resolve(null);
      }
    });
  });
}

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

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

  // ユーザーが入力した地域情報を取得
  const cityName = event.properties.preferences.cityName;

天気情報を取得

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

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

Http通信用に追加したnodeモジュールrequestを使用して通信を実現しています。
アクセス先のurlOpenWeatherMapの仕様に準拠しています。
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));
        // レスポンスのBodyを返却
        resolve(JSON.parse(response.body));
      } else {
        console.error('getWeatherInfo: responce = ' + 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をアップロードする」をご覧ください。