Using the Lambda environment to create Pieces

Contents

This article will show you how to create a Piece without having to understand the behavior of the native code of your smartphone or the SDK. You can create an S/A piece by implementing code that runs on Lambda. In operation, the SDK and PieceCore cooperate in calling a function on Lambda.

We prepared an environment where you can code without having to be aware of the behavior shown above. With the SDK and smartphone serving as your “black box” on the side, you can save time you would otherwise have to spend developing the smartphone implementation and instead focus completely on developing Javascript on Lambda.

From here, we’ll cover an example of Node.js development. As seen in the above figure, you can then begin your Piece development by defining the PieceJSON key as follows.

"blockType":"service", // If you want to make an Action Piece, enter “action” here instead of “service”
"executor":"RBCCommonWebServiceExecutor", // This section captures the PieceCore which is built into the SDK. You need to use this
"serviceProxy":{
  "service":"pieceCore_Sample" // The name of Javascript file on Lambda that you create, without the .js notation
},

With the above key included in your PieceJSON, let’s also consider the operation after your Javascript file is called.

Riiiver has a web tool called PieceBuilder. It acts like a file uploader and allows you to place files onto the Lambda prepared by Riiiver. This is shared with other developers and ends up looking like the following figure.

When a user runs an iiidea using your service piece prepared in Lambda, the script with the file name defined as "service" in the "serviceProxy" section of the PieceJSON is executed.

The actual Javascript code with the usual Lambda is shown below.

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

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

  //.... your process here ....

  //.... Return the response .....
  return response;
};

When your Piece’s execution order is reached, this handler is called. In exiting from this handler, it is necessary to store and return JSON data as defined in the response variable’s return value. The data enclosed in {...} defined in the body: of the "response" section is the data passed to the next Piece. For example, if you upload the code shown above as a Piece, the output of this Piece will be {0.0}.


Preparing a local debugging environment

Even though your created piece may work immediately when uploaded to Lambda, the development will be difficult if you can’t debug your code before uploading it. This section describes how to debug your code locally.

Preparation

We will use the following tools for debugging, so please install them (we cannot confirm functionality using other tools, so please use those linked above).

In the sample code, we will use a service called OpenWeather that provides a REST-API to get weather data. To obtain weather information using this API, let’s first register for API usage.

1. Go to OpenWeather to create an account.

2. Register the information needed to create an account.

3. OpenWeather will send you the following confirmation email to the address registered with them.

In this email, Your API Key is 98d2 ... c is the key required when using the API. Make a note of this.

4. Operation check.

You can also find in this email (after Example of API call) a sample API call utilizing your specific API key. The default example shows how to get current weather information for London. Click this URL and, if the following page is displayed, you’re good to go.

Now let’s check the operation in the local environment. First, download the sample code.


Extracting the sample code

Sample code structure

When you extract the sample code, you should see the following files and folders.

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

✏️ = Files for you to edit. Edit the content, but do not move.

  • SampleCode – The root folder of the sample project.
    • .vscode – VS Code setup file.
    • kicker_on_lambda.js – A kicker that simulates the trigger of Riiiver’s Lambda environment.
    • YourCode – The folder that includes your code.
  • JSON – The folder that stores the PieceJSON that you created.
    • pieceJS_Sample.json – A JSON file you need to describe. The name of the file is up to you. The file extension must be ‘.json.’
  • ProxyCore – The folder that stores the PieceCore that you created.
    • pieceCore_Sample.js – The body of the PieceCore. The file name is free, but it must match the file name you specified in the PieceJSON.
    • package.json - This file summarizes the dependencies of the modules used in pieceCore_Sample.js.
  • event.json – Data passed on to the PieceCore. This file simulates data such as the output from the previous Piece and the user setting information.
Understanding the behavior of Pieces in the local environment

The sample code can be executed as-is. Let’s run it in the local environment and see how it works!

It is important to understand how the Piece operates on Lambda. Even in the local environment, it is configured to operate as close to the actual Lambda environment as possible. However, instead of Lambda, PieceDebugger/kicker_on_lambda.js will execute your code. You don’t need to read the source code for this tool, but, by calling this javascript, you can emulate the behavior that will be triggered in your piece by Lambda when the previous Piece process finishes.

Sample Code 
├── .vscode 
├── kicker_on_lambda.js // This emulates the process when Lambda triggers your code.
└── SampleCode
    └── YourCode
        ├── JSON
         ....

 

API Key Settings

First, you need to set the API Key you obtained to the sample code. Let's open the sample folder with VS Code.

Open the ‘SampleCode’ folder.

Notice
Don’t mistake the hierarchy!

Click SampleCode/YourCode/ProxyCore/pieceCore_sample.js to open the file. Enter your API key as the apikey variable, as if enclosing the key string in quotes (""). Don’t forget to save after this code rewrite.

Install required node modules

In this example, we will use HTTP communication method to call REST APIs on the web. Here we use a module called axios to implement the HTTP protocol easily. Execute the following command to install the axios module.

1. Move the current console position to the location of the sample code (Javascript).

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

2. Add the `npm` command to install required node modules.

npm install

3. This file installs necessary libraries into the `node_modules` folder in accordance with `package.json`.

Now you are ready to use the communication module.

Execute the sample in Terminal

Let's run it now.

For Linux / Mac, first open the Terminal app. Open the Command prompt for Windows to go to the SampleCode directory.

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

And type the following command:

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

You should get the following results, but note that this may not work correctly when the environment in which you are operating is behind a 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.data = {"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}
output:  {"status":200,"body":{"celsiusTemperature":24.04000000000002}}
Your Function Output ::  {"status":200,"body":{"celsiusTemperature":24.04000000000002}}

A variety of data is logged here, but the data that will be output from your Piece (and sent on to the Action piece if you’ve built a Servie piece) is captured in the body key on the last line:

{"celsiusTemperature":24.04000000000002}}

Now let’s dig a little deeper using this actual implementation to confirm our understanding of the operating flow and the PieceCore.

Piece Debug behavior

We did our test using the Terminal / Command Prompt earlier, but you can debug the operation using VS Code (to set breakpoints, use the file watcher, etc.). Effective debugging will make your Piece more efficient, so let’s give it a try.

Debugging environment settings

Open the project folder "SampleCodeName" using VS Code, just as you did when setting the API Key. Click the debug button (the button that looks like an insect) in the panel with the icons on the left side of the program.

Clicking this button will bring up the debug screen. Next, we will set the file to be executed during debugging. Click the gear button circled in the figure below.

This will take us to the edit screen for launch.json, which is the setting file for the VS Code debug environment. Here, let’s change the contents in the program field as shown in the image above. Set program to run kicker_on_lambda.js by entering the following code.

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

Since the debugging function of node.js is built into VS Code as standard, it is not necessary to install any further extensions. As the name suggests, kicker_on_lambda.js calls the code you have described in your PieceJSON instead of AWS Lambda.

Now you’re ready for debugging… so let’s debug it!

You can also set breakpoints in your code using the VS Code program. First, let's set a breakpoint in kicker_on_lambda.js to make sure that the debugging environment is set up correctly and that kicker_on_lambda.js is running successfully.

  1. Click the file icon on the left side of the screen to display the project folder.
  2. Click the kicker_on_lambda.js file to view the source code.
  3. Select the kicker_on_lambda.js tab on the top of the screen (if not already selected).
  4. Click on the left part of the 9th code line to add a red circle to mark your breakpoint.

If this works correctly, when kicker_on_lambda.js is executed, it should pause when it reaches line 9.

Debug doublecheck

Let’s keep debugging!

  1. Click the insect icon again to enter debug mode.
  2. Debugging will start again when you click the playback arrow button circled below in orange.

If it functions correctly, it should take once more pause at the breakpoint set on line 9, as shown below.

At this break, you can check local variables and global variables via the VARIABLES panel on the left side of the screen. You can also check value and status data at the breakpoint by hovering the mouse cursor over any variable in the source code.

If you want to continue running your operation, click the ‘Play’ arrow button circled in light blue in the image above.
If the sample code operates correctly, you can navigate to the DEBUG CONSOLE in VS Code to investigate the console.log() output:

You should be able to find the same information as above via Terminal as well:

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

Preparing the PieceJSON

When we discuss preparing the PieceJSON, we are talking about preparing the specifications of the Piece. Some PieceJSON files confirmed to work well are included in the sample project, such as YourCode/JSON/pieceJson_Sample.json. This is the same PieceJSON we’ve been using for the explanation so far.

You can change PieceJSON file names as you wish, but remember that the extension must be ‘.json.’

{
    "title": {
        "en": "Current Temperature (celsius)",
        "ja": "現在の気温 (摂氏)"
    },
    "version": "1.0.0",
    "sdkVersion": "1.0.0",
    "deviceId": "none",
    "vendorId": "none",
    "description": {
        "en": "~~What is this Piece?~~\nGet the current temperature in degrees Celsius (°C).\n\n~~How do I use it?~~\nInclude this Piece in an iiidea to output a simple number representing the current temperature in °C.\nYou can choose in the iiidea settings for where to get information.\n\n~~Notes~~\nThe output value will be -50 if this Piece cannot get information due to network or a separate error.\n\nAbout Trademarks ( https://riiiver.com/en/trademark/ )",
        "ja": "【どんなPiece?】\n現在の気温を摂氏で次のPieceに渡します。\n\n【どうやって使うの?】\n「地域」のドラムロールから、気温を知りたい場所を選択してください。\n\n【ご注意!】\n気温をうまく取得できなかった場合は値が -50 となります。\n\n商標について ( https://riiiver.com/trademark/ )"
    },
    "blockType": "service",
    "executor": "RBCCommonWebServiceExecutor",
    "serviceProxy": {
        "service": "pieceCore_Sample"
    },
    "pieceCapability": "notUse",
    "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"]
}

Again, the important keys here are "executor" and "ServiceProxy".

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

The value of "executor" always needs to be "RBCCommonWebServiceExecutor" to run on the Lambda prepared by Riiiver. The value specified as the "service" in "serviceProxy" should be set using the javascript filename corresponding to your created logic (excluding the ‘.js’ from the filename). In the above example, you can see that Lambda calls the handler of the pieceCore_Sample.js file. We will touch on .js files more shortly.

Understanding preferences

Critical information contained in the sample data above is enclosed under "preferences".

Preferences define the settings that you want end-users to select before your Piece runs as part of an iiidea. The user will set their preferences from their individual iPhone/Android device. For example, the pieceJson_Sample.json preference data above will display the following options to the user.

Let’s better understand how the preference data in the JSON translates to this UI.

First, "type" should always be set as "Object". The key specified in "properties" should then be the name of the value to be set by the user. Here we’ve entered "cityName". How this value will be defined then follows this key, and here we’ve chosen a "string" format. Possible string value definitions are then found in the enum, so one of the following values can be set as a "string".

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

If the user does not select a value, the Piece will use the value you set as the "default". In this example, the "default" is set to "Tokyo". The other keys starting with "x-" here (x-title, x-description) are related to further UI specifications, which we’ll explain in the following section.

x-input-type

You can specify the type of user interface (UI) displayed to the user here. The following UI can be offered to the user as a means to set the preference information.

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

In the current example, we’ve used a drumroll.

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

The x-title is for naming each preference section with a title that makes clear to the user the preferences that you want them to set. ‘Area Setting’ is what has been set as the x-title. Note that you can include titles for multiple languages using established language codes.

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

A simple description that will appear below the x-title and make even more clear what preferences you want the user to set. Here, “Set the area from which to get the temperature.” is shown to the user to instruct them on choosing a location.

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

You can see here that each selectable preference value corresponds to an enum value. Please additionally note that, if the value to be set in the code is different from the value information you want to actually display to the user, you can set the human-readable string that is shown to the user to be something different. For instance, in this case the city name ID value has to be set based on the value set and data received from OpenWeatherMap; however, we can change that to display a string of our choosing. So although Sapporo-shi is the required value defined by the OpenWeatherMap data, we can set the display to something more easy to understand for the user, such as simply “Sapporo” for English speakers, or the well-known kanji characters for Sapporo to Japanese users.

The Preference UI in practice

By drafting your PieceJSON as described, you can create this kind of UI that will allow users to configure their preferred information for your Piece. So of course you want to test to make sure everything is going to display to users as you’re expecting, right?

For this purpose, we’ve prepared an online PieceDebugger serving as a simulated user environment. Using our PieceDebugger you can confirm whether or not the Preference UI is formatted correctly in the JSON file such that the preference values display to the user as desired.


Using the PieceJSON Generator

Let's check to see whether your PieceJSON file can generate the UI correctly. PieceJSON Generator is provided as an online editor, so visit https://piecejson-generator.riiiver.com/ to access it. The following screen should appear.

Copy and paste the PieceJSON file included in the sample code, or select to open the file. Your screen should look something like this:

Checking the PieceJSON format

To check whether your PieceJSON format is correct and that you properly defined all required key items, click "Check Piece Format" in the "Debug" menu.

Your result will be displayed in the bottom panel of the screen.

If there are any errors, check the error messages to identify where corrections are needed.

Checking the Preference UI

If you’ve included Preference setting items in your PieceJSON, you can check how it is displayed to the user using the PieceDebugger.

Click "Preview" in the menu and select the language of the user interface you want to preview (English or Japanese).

In the example above, we’ve selected to view the Preference UI as it will appear to English users. The preview will be displayed in the right panel of PieceDebugger.

We’ve created a Service Piece here, so the preferences you’ve asked the user to select are displayed in the S Service section. (Note that the PieceDebugger is used to check just 1 Piece alone, but when the user encounters the Preferences screen, he/she will see information regarding each of the T, S, A pieces that make up the iiidea. The PieceDebugger shows how your Piece will appear in a total iiidea configuration; however, there is no display for any Piece other than yours. The title of the iiidea is also a dummy placeholder).

You can interact with the right panel to set preference values as if simulating an end-user experience, and then you can check/debug each individual preference choice. To test this, let’s click on the drumroll under "Area setting" and select "Osaka." Then, click the "Debug" button on the menu and click the "Check Preference" option.

In the bottom panel (the debug console) you should see your preference code:

preferences: {"cityName":"Osaka"}

This JSON value is the data that the user (in this case, you!) has set based on the preference UI offered in your PieceJSON. Using this information, you can debug your Piece as if monitoring a live user experience.


Guideline for PieceJSON's description

There are some rules on making a description to be referred.


Input/Output

In your PieceJSON, you need to define the type of data that your Piece can receive as input data, as well the type of data that will be output from your Piece to the next Piece (or to the device).

When a Riiiver user creates iiidea, after selecting their first Piece, they will only then be able to select to connect it to other Pieces that match the required input/output type. Think of it like connecting pieces of a puzzle, or linking together sections of a train track. If your Piece only accepts “Type A” input data, then the user will be able to place Pieces that output “Type A” data in front of yours. If your Piece only outputs “Type B” data, Pieces that don’t accept “Type B” data will not be shown as Pieces that the user can link after yours.

Input

The sample pieceJson_Sample.json file does not yet have an input key, so this Piece cannot receive any input until we make some edits. In order to accept input, let’s add the following code:

"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

The following output is already set in the sample code:

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

Note that this Piece outputs “number” data, specifically "celsiusTemperature" key data that we are calling from our weather data service.


Understanding the Runtime Data Flow

At this point, we hope we’ve made somewhat clear the details of the PieceJSON. Please continue to refer to this page when making your own!

Let’s now then take a look at how the data flows when a Piece is actually run by a user.

Data Passed to the Piece - event.json

Data sent to the Piece contains the following values, including the Preference data we’ve described above.

  • Preference
  • Input
  • Parameter
  • userData
Preference

Settings data that is set by the users, such as the location setting data demonstrated previously on this page {e.g., "cityName": "Tokyo"}. End-users select the preferences via the various UI featured on Riiiver devices. Refer to this page (INSERT LINK) for information about the various UIs.

Input

The data sent to your Piece from the previous Piece.

Parameters

In addition to the input value data you receive from the previous Piece, you can also retrieve various information from the user’s smartphone if they’ve granted the necessary permissions. For example, you can currently get the GPS coordinates of the user’s smartphone.

This various information delivered to the Piece is then inserted into your json file as below, to be exchanged with Lambda when executed.

userData

Setting information collected from the user's smartphone is delivered as userData.
The following items are included in userData:

  • date: Get the local date/time as set in the user's smartphone.
  • languageCode: Get the language the user has set on their smartphone.
  • countryCode: Get the home country the user has set on their smartphone.

This various information delivered to the Piece is then inserted into your JSON file as below, to be exchanged with Lambda when executed.

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

The data passed to the Piece in the Local environment is recorded as YourCode / event.json, and it allows us to check the operation and debug.

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

If you press the debug button at the top right of the screen, any values you set as Preferences using the UI emulator will be entered as the Preferences in the YourCode / event.json file.

The data defined in the above event.json file should also be effectively captured as input when Kicker_on_lambda.js is executed via Terminal or Command Prompt.

Set a breakpoint and debug

Now let’s use breakpoints to check the contents that that event.json file is actually delivering to the Piece. We’ll use VS Code again so that we can easily set breakpoints anywhere we want.

Post-Lambda operation

First let's set a breakpoint to occur immediately after the function shown in exports.handler is called, assuming that your code is executed in Lambda on AWS. In the sample code (pieceCore_Sample.js), find the file named 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 (axios !== null) { }

    return;
  }
  ...
Do not erase or edit the "if" statement on line 11 (line 17 in the sample code) for now.
Please ignore it, though, as it has another role. It's just not a typical case, so we'll explain it later.

Here the console log occurs on precisely the 29th line, so let's put a breakpoint right there.

Now press the insect button again to run the script. The information will be passed to the Piece as an event variable, so let's take a look inside the event. There’s a section called "WATCH" on the left panel of the screen (circled in orange below). Press the "+" button to the right of that to enter the event detail.

Here you can see the contents of the event variable, which is actually a JSON object entered as event.json.

In the orange box you can see that {cityName: "Tokyo"} has been captured as the user preference data.

Now set a breakpoint on the sixth line and so that you can confirm the output of the console.log from the 29th line and verify the actual event contents. The result should look like this:

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

The data entered and set in the Piece has been processed as an event, so let's take advantage of this variable and process it.


Execute your PieceJSON and send your result onwards

Runtime Process

Let's check the sample code processing one more time. Our target code that we intend to process on Lambda is specified as pieceCore_Sample.js in the PieceJSON.

We’ll go through and explain the main points one by one.

'use strict';

/* If your code uses external modules, create instances here. - 外部モジュールを使う場合はここでインスタンスを生成してください。
   e.g.  const axios = require('xxxx');   // xxxx : external module - xxxxは外部モジュール */const axios = require('axios');

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 (axios !== null) { }

    return;
  }

  /* Start coding here - これ以降にコードを記入してください。*/
  console.log('start: event = ', JSON.stringify(event));

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

  const cityName = event.properties.preferences.cityName;     // Get the location information entered by the user - 自分のpieceのプリファレンスの値
  const urlString = `${apiHost}${apiPath}?q=${cityName},jp&APPID=${apikey}`;  // Combine strings and make the URL - URLの文字列を完成させる。
  console.log('urlString: ', urlString);

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

  // Get today's weather information - 天気情報から今日の情報を取得
  if (weatherData) {
    const tempK = weatherData.main.temp;           // Save the temperature in the obtained JSON. The unit is Kelvin. - REST APIから得られたJSON内の温度を保存。単位はケルビン。
    response.body.celsiusTemperature = tempK - 273.15;  // The value sent to the next block will be the temperature in Celsius (Number) - 次のブロックに返す値は摂氏で数値(Number)
  }

  console.log('output: ', JSON.stringify(response));

  return response;
};

function getWeatherInfo(urlString) {
    console.log('getWeatherInfo: start');
    
    const options ={
      url : urlString,
      method : 'get',
    }
  
    return axios.request(options)
    .then(function (response) {
      console.log('getWeatherInfo: response.data = ',JSON.stringify(response.data));
      return response.data;
    })
    .catch(function(error){
      console.error('getWeatherInfo: response = ', JSON.stringify(error));
      return null;
    });
  }
Processing the first "if" statement

Do not erase or edit the code block that begins with: if (event.call === 'lambda') {
This is the code needed to "Warm Start" your Lambda function, which is a mechanism we have prepared on the Riiiver side to allow quicker Lambda execution. To enhance the end-user experience, the Riiiver system makes routine calls to all of our hosted Lambda functions on the backend at set intervals with the purpose of speeding up your Lambda response.

Consider an example in which we are using an external module that can consume serious time just to initialize. By fitting this "if" statement code into the external module, things can be prepped for takeoff. What we are doing is attaching an "async" keyword to run work in a separate thread, asynchronous with actual user Lambda use. Here's what happens:

Your Lambda function is called for execution. When the program attempts to process if (axios !== null), it may find that the global axios variable and defined axios module have not yet been initialized. This function guarantees that the axios module is initialized before trying to move on to evaluate the next part of the conditional "if" statement. As you probably noticed, we didn't put anything after that statement ("null"), but now this big external module that we were worried would take a lot of time to initiate and would therefore ruin the user experience has been initalized and is all ready to go when the next user calls.

In other words, the external module instance is cached in memory in an initalized state, thanks to this periodical calling of the "if" statement.

When using an external module, declare it as a global variable under 'use strict'; and then also put the process that uses this declared variable within the if (event.call === 'lambda') code block. If everything is coded accurately, you should see an increase in the response speed of your function.

Get the region information entered by the user

This example demonstrates a use case where a user wants current temperature information for their preferred location.

The “cityName” value is entered here in accordance with the requirements of OpenWeatherMap, so that we can effectively retrieve our desired data from their service. The information in the event.json file will then be processed as our Piece input data and stored in the event variable. User preference setting information is accessed and extracted as shown below.

// Get the location information entered by the user  
const cityName = event.properties.preferences.cityName;
Get Weather Information

Here’s the process that actually gets the weather information.

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

Successful communication with the service is achieved by using a node module axios added to facilitate http communication.

The URL of the access destination conforms to the required specifications of OpenWeatherMap.

By querying the weather service (at https://api.openweathermap.org/data/2.5/weather) with the id = cityName value, we should receive weather information for the area specified by cityName.

function getWeatherInfo(urlString) {
  console.log('getWeatherInfo: start');
  
  const options ={
    url : urlString,
    method : 'get',
  }

  return axios.request(options)
  .then(function (response) {
    console.log('getWeatherInfo: response.data = ',JSON.stringify(response.data));
    return response.data;
  })
  .catch(function(error){
    console.error('getWeatherInfo: response = ', JSON.stringify(error));
    return null;
  });
}
Create Output Data to Send Onwards

We’ll now take the information we received about the current information in our user’s preferred location and turn it into output data.

// Get today's weather information - 天気情報から今日の情報を取得
  if (weatherData) {
    const tempK = weatherData.main.temp;           // Save the temperature in the obtained JSON. The unit is Kelvin. - REST APIから得られたJSON内の温度を保存。単位はケルビン。
    response.body.celsiusTemperature = tempK - 273.15;  // The value sent to the next block will be the temperature in Celsius (Number) - 次のブロックに返す値は摂氏で数値(Number)
  }

The format of the value returned by the Lambda function always appears like the below HTTP result, to be sent on as output data to the next Piece.

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

And that concludes our explanation of the sample code!

There are other functions that can be realized on Lambda, so please check out our section on Extending the functions of Piece to discover even more.

For instructions on how to upload your created and debugged Piece, navigate to the Uploading a Piece section.


Was this page helpful?