更新 2020/11/01
Piece の動作部分 (Lambda編)
どうも、こんにちは!JellyWareです。
Getting Started!! Riiiver tutorialの第12弾となります。
このシリーズは、Riiiverやプログラミングを学び、初心者の方でもEco-Drive Riiiverを活用したオリジナルアプリを理解して作れるようになることを目指します。
今回は、Piece の構成要素の1つ「PieceCore」について説明します。
また、Riiiver が用意している Lambda を利用する場合について絞って解説をします。
目次
PieceCore とは
PieceJSON が Piece の仕様書であるのに対して、PieceCore は Piece の 本体と言え、どのような動作を行うのかを決定します。
具体的には、プログラミング言語を使用して記述された動作部を「PieceCore」と呼び、Riiiver が用意したモノとユーザーが作成するモノの2種類があります。
PieceCore はスマートフォンアプリ内に作成する必要があるため、アプリの開発者しか作れません。しかし、アプリの開発をしなくてもオリジナルな Piece を作成できる仕組みがRiiiverには用意されています。
Lambda を使用する場合の PieceCore
ここで、登場するのが AWS の Lambda となります。
「動作部である PieceCore は、スマートフォンアプリ内に作成する必要がある」と先ほど説明しましたが、Lambda にソースコードをアップロードすることで PieceCore のように機能させることができます。
流れとしては、
「Piece の実行」 → 「PieceCore の実行」 → 「Lambda 上のソースコードの実行」 となります。
では、この時に使用される PieceCore は何になるのでしょうか?
答えはRBCCommonWebServiceExecutor
で、Riiiverが用意する PieceCore です。
以降、「Lambda 上のソースコード」を「PieceFunc」と便宜上呼びます。(Func は、Functionの省略です。)
簡単に図にすると、こういった流れになります。
つまり、皆さんは「PieceFunc」を作成することで Piece を作成することができます。
※Lambda を使用する場合、作成できるのは Service / Action Piece のみです。
Lambda を使用する場合の PieceJSON
Lambda を使用する場合、PieceJSON のフォーマットが一部固定となります。
前回説明していますが、以下のkey
について改めて説明します。
- deviceId
- vendorId
- executor
- serviceProxy
"deviceId": "none"
対応するデバイスを指定する必要がない場合、"none"
を指定できます。
"vendorId": "none"
"none"
を指定します。
"executor": "RBCCommonWebServiceExecutor"
"RBCCommonWebServiceExecutor"
を指定することで、Lambda上の Piece Func を実行できるようになります。
"serviceProxy" : {
"service": "serviceSample"
}
"serviceProxy"
内の"service"
に、Lambda 上の PieceFunc となるファイル名を指定します。(拡張子は不要です。)
例えば、serviceSample.js
と言うファイルを実行する場合は、上記のように"serviceSample"
と指定します。
PieceFunc
それでは、Lambda にアップロードする PieceFunc について解説していきます。
サンプル
以下、サンプルの PieceFunc です。(一部割愛しています。)
'use strict';
exports.handler = async (event) => {
// 受け取った情報をログで出力しておく
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;
};
基本的には、今まで習った JavaScript の文法に従ってコードを記述すれば問題ありませんが、いくつか決まり事があります。
フォーマット
Lambda と Riiiver の仕様で、PieceFunc にもフォーマットがいくつかあります。
PieceJSON 同様、最低限必要となるコードを使用して解説します。
exports.handler = async (event) => {
const response = {
status: 200,
body: {
outputData: "成功"
}
};
// 処理
// 結果を返す
return response;
};
上記が最低限記述したコードです。2つに分けて解説します。
exports.handler = async (event) => {
// 処理
};
Piece が実行されると、このアロー関数が自動的に実行されます。
また、引数のevent
は以下のようなJSONデータです。
{
"serviceProxy": "samplePieceCode",
"properties": {
"preferences": {
"prefrenceData": "samplePrefrenceData"
},
"input": {
"inputData": "sampleInputData"
},
"parameters": {}
}
}
"serviceProxy"
は、使用する Lambda 上のコード名がvalue
となります。(.js
などの拡張子は省かれます。)
"properties"
は、以下の3つのデータがvalue
となります。
"preferences"
:アプリからユーザーが入力したデータ"input"
:前の Piece から受け取るデータ"parameters"
:端末の情報(位置情報など)
("parameters"
に関しては、別途解説するため空にしています。気になる方はこちらを参照してください。)
また、"preferences"
と"input"
は、PieceJSON の"preferences"
と"input"
とそれぞれ紐づいています。
"preferences": {
"type": "object",
"properties": {
"prefrenceData": {
~
}
}
}
"input": {
"type": "object",
"properties": {
"inputData": {
~
}
}
}
今回の例で言うと、それぞれの"properties"
内にある"prefrenceData"
"inputData"
が紐づいている箇所になります。(このkey
名は、みなさんで自由につけられます。)
PieceJSON で指定したkey
名がevent
変数内のJSONデータで使用されることになります。
次に残りを解説します。
const response = {
status: 200,
body: {
outputData: "成功"
}
};
// 処理
// 結果を返す
return response;
Riiiver の仕様で、戻り値のフォーマットが固定となっています。
{
status: 200,
body: {
outputData: "成功"
}
}
型はオブジェクトで、status
とbody
の2つのkey
が必要です。
status: 200
Piece が正しく動作したことの目印として、status
に200
を指定します。(HTTPステータスコードと呼ばれるものです。)
例えば、try…catch文を利用して Piece が正しく動作しなかった場合には、status
に500
等のエラーコードを指定することでRiiiverにエラー内容を伝えることができます。
body: {
outputData: "成功"
}
body
には、次の Piece に渡すデータを設定します。型はオブジェクトです。
この例だと、outputData
に指定している"成功"
が次の Piece に渡されるデータです。
また、PieceJSON の"output"
と紐づいています。
"output": {
"type": "object",
"properties": {
"outputData": {
"type": "string"
}
}
}
今回の例で言うと、"properties"
内にある"outputData"
が紐づいている箇所になります。(このkey
名は、みなさんで自由につけられます。)
PieceJSON で指定したkey
名を変数名として使用する必要があります。
※以下、2020年6月24日に追記
if (event.call === 'lambda') {
if (axios !== null) { }
return;
}
Lambdaの動作を素早くするために、上記のようにウォームアップコードを追記する必要があります。詳細については、Riiiverのチュートリアルをご参照ください。
if (event.call === 'lambda') {
if (xxxxxx !== null) { }
return;
}
基本コードが上記となり、xxxxxx
の箇所を読み込んだモジュールに変更するだけとなります。例えば、const axios = require("axios");
と読み込んでいるのでaxios
に差し替えれば問題ありません。
複数のモジュールを扱う場合はif (xxxxxx !== null) { }
を追加しましょう。
作成例
例えば、ユーザーがアプリから入力した「太郎」、前の Piece から「おはようございます」を受け取り、次の Piece に「おはようございます、太郎さん」を渡す PieceFunc を考えます。
以下の JavaScript のコードを埋める形で、PieceFunc を作成します。
exports.handler = async (event) => {
// 処理
};
まずは、event
変数のデータがどのようになるか確認しましょう。
(今回は、PieceJSON は考えないため一部のkey
,value
は仮となります。)
{
"serviceProxy": "serviceSample",
"properties": {
"preferences": {
"name": "太郎"
},
"parameters": {},
"input": {
"greet": "おはようございます"
}
}
}
ユーザーがアプリから入力したデータは"preferences"
、前の Piece から受け取ったデータは"input"
に、それぞれ渡されます。
("name"
,"greet"
は、PieceJSON で指定したkey
名となります。)
次に、PieceFunc の方でそれぞれのデータを抜き出しましょう。
exports.handler = async (event) => {
const name = event["properties"]["preferences"]["name"]; // 追加
const greet = event["properties"]["input"]["greet"]; // 追加
};
event
は、JSONデータのため、key
を指定してvalue
を抜き出すことができます。
次にこの抜き出したデータを使って、次の Piece に渡しましょう。
exports.handler = async (event) => {
const name = event["properties"]["preferences"]["name"];
const greet = event["properties"]["input"]["greet"];
const nameAndGreet = `${greet}、${name}さん`; // 追加
};
文字連結を行い、戻り値となるresponse
の形式を Riiiver用に整えています。
exports.handler = async (event) => {
const name = event["properties"]["preferences"]["name"];
const greet = event["properties"]["input"]["greet"];
const nameAndGreet = `${greet}、${name}さん`;
const response = { // 追加
status: 200,
body: {
output: nameAndGreet
}
}
};
今回は、シンプルに成功のみにしています。そのため、status
には200
を指定します。
output
は、PieceJSON のoutput
で定義したkey
名と合わせる必要があるので注意してください。
exports.handler = async (event) => {
const name = event["properties"]["preferences"]["name"];
const greet = event["properties"]["input"]["greet"];
const nameAndGreet = `${greet}、${name}さん`;
const response = {
status: 200,
body: {
output: nameAndGreet
}
}
return response; // 追加
};
最後にreturn
で、次の Piece に渡すデータを返しています。
これで完成です。コツとしては、以下の3つになるかと思います。
event
内のJSONデータを確認するevent
から必要なデータを抜き出す- 次の Piece に渡すデータを作成する
特にevent
内のJSONデータについては、Riiiver の仕様で決定されるものです。形式などを忘れた際には、改めて本コンテンツか公式のドキュメントをご確認ください。
Lambda を使用する場合の Piece Core について理解できたでしょうか?
RBCCommonWebServiceExecutor
の PieceCore を指定すること- PieceFunc を作成すること
Piece を作る上で重要なことは、この2点です。
次回は、今まで学んだことを活用して1つの Piece を作成します。
ご覧くださりありがとうございました。