Force.com Canvasのsigned-requestを検証&デコードするNode-REDノード

Node-REDは主にIoT領域でサービス連携に使われてますが、[Node-RED を使用してリアルタイムのチャット・アプリケーションを 5 分で作成する](http://www.ibm.com/developerworks/jp/cloud/library/cl-rtchat-app/)のようにWebページ/アプリケーションを作ることも可能です。

ということは、SalesforceのCanvasを使えばNode-REDで作成したWebアプリケーションがSalesforce内で使える！ということで、このたび[node-red-contrib-force](https://www.npmjs.com/package/node-red-contrib-force)にSigned Requestを検証&デコードするノードを作りました。

以下、チュートリアル的に紹介します。

## Node-REDをHerokuで動かす

Node-REDをHerokuで動かすには以下のHerokuボタンをクリックしてください（以下、例として https://node-red-123.herokuapp.com にデプロイしたものとします）

[![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy?template=https://github.com/joeartsea/node-red-heroku)

何もしないとNode-REDのエディタ画面がフルオープンになってしまうのでHerokuの環境変数として`NODE_RED_USERNAME`と`NODE_RED_PASSWORD`を必須としてます。ユーザ名とパスワードを決めて入力したら "Deploy for Free" ボタンをクリックしてください。

<img width="912" alt="スクリーンショット 2015-12-22 14.53.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/1fc03a74-4507-0be9-d8f5-733059e50c55.png">

デプロイしたらホストにアクセスしてみます（今回の例ですと https://node-red-123.herokuapp.com ）以下のような画面が表示されますので "Go to your Node-RED flow editor" ボタンをクリックします。

<img width="1174" alt="スクリーンショット 2015-12-22 14.56.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/e63a4c32-a9bb-bff2-1f11-b14b6185594c.png">

するとログイン画面に遷移しますので先ほどHerokuデプロイ画面で設定したユーザ名とパスワードを入力してログインします。

<img width="1174" alt="スクリーンショット 2015-12-22 14.58.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/4ddd9698-9015-2f00-3e29-8b8ec072aec7.png">

これで以下のようにNode-REDエディタ画面が表示されればOKです。今後、直接エディタ画面を開くには`/red`を付与してアクセスします（今回の例ですと https://node-red-123.herokuapp.com/red ）

<img width="1172" alt="スクリーンショット 2015-12-22 15.01.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/03db75b9-25c4-a3a0-b684-6c940daac448.png">

あとは今回紹介する[node-red-contrib-force](https://www.npmjs.com/package/node-red-contrib-force)というモジュール/プラグイン的なもの（Node-REDでは一つ一つのモジュール/プラグイン的なものをノードと呼びます）をインストールします。

[node-red-contrib-force](https://www.npmjs.com/package/node-red-contrib-force)を使うには、`npm install -g node-red-admin`で[node-red-admin](https://www.npmjs.com/package/node-red-admin)をインストールして以下のコマンドを叩きます。

```
$ node-red-admin target <Node-REDのエディタ画面のURL 例:https://node-red-123.herokuapp.com/red>
$ node-red-admin login
Username: <Herokuにデプロイする時に設定したユーザ名>
Password: <Herokuにデプロイする時に設定したパスワード>
Logged in
$ node-red-admin install node-red-contrib-force
Module:    node-red-contrib-force
Version:   0.0.6                 

Nodes                                               Types                  State  
node-red-contrib-force/chatter                      force-chatter in       enabled
node-red-contrib-force/forcedotcom                  force                  enabled
                                                    force in                      
node-red-contrib-force/forcedotcom-bulk             force-bulk in          enabled
node-red-contrib-force/forcedotcom-signed-request   force signed request   enabled
```

## Node-REDでWebページを作成する

まず、以下のようにHTTP Inputノードをドラッグ&ドロップしてワークスペースの好きな場所へ置きます。

<img width="1173" alt="スクリーンショット 2015-12-22 14.42.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/6ed476cd-47cb-65e6-6be7-c6b14490ad90.png">

次に配置したノードをダブルクリックするとノード定義用の設定ダイアログが開きますので以下のようにHTTP Inputノードに`/canvas`というURLを設定します。これだけでNode-REDが動くHTTPのGETメソッドのエンドポイントを作成できます。

<img width="1175" alt="スクリーンショット 2015-12-22 14.45.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/bbb7e963-0ce7-ffc9-f5a0-f0b7bcf42f94.png">


あとは表示するWebページを定義するTemplateノードとHTTP Outputノード（HTTPレスポンス）と念のためDebugノードを以下のように配置してDeployボタンをクリックします。上記でエンドポイントを定義したHTTP Inputノード以外はデフォルトのまま（配置してつなぐだけ）で良いです。

<img width="1173" alt="スクリーンショット 2015-12-22 14.38.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/c81be80f-9543-b05b-1c7e-d318f7dee6c1.png">

ここまでできたところでNode-REDをデプロイしたホストにHTTP Inputノードで定義したエンドポイント（今回の例ですと https://node-red-123.herokuapp.com/canvas ）へアクセスしてみます。

<img width="507" alt="スクリーンショット 2015-12-22 14.20.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/c927abae-f3c2-9f50-e106-c14dfa505804.png">

Templateノードがデフォルト定義のままなので`[object Object]`となってますがWebページが返ってきました。

続いて先ほどのURLに`?aaa=111`というパラメータを付与して（今回の例ですと https://node-red-123.herokuapp.com/canvas?aaa=111 ）アクセスしてみます。

表示されるWebページは変化ありませんがNode-REDのエディタ画面に戻るとデバッグに送信したパラメータが表示されています。

<img width="1174" alt="スクリーンショット 2015-12-22 14.24.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/18ffe898-5f07-8f71-3b49-e7dcd9370121.png">

これはHTTP Inputノード（`[get] /canvas`）で受け取ったパラメータをNode-REDがJSONに変換して`msg.payload`というプロパティにセットしてDebugノードへ流した結果です。

<img width="1172" alt="スクリーンショット 2015-12-22 14.26.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/73e7fd73-2f18-1dd4-ddea-1f312a2c258a.png">

これでNode-REDのノード同士を接続するラインを流れるメインのデータは`msg.payload`を流れているのが解るのでTemplateノードを以下のように変更してみます（Templateノードをダブルクリックすると設定ダイアログが開きます）

```
This is the payload: {{payload.aaa}} !
```

<img width="1176" alt="スクリーンショット 2015-12-22 14.32.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/9a9cc5bb-84b8-63ec-2f70-da6049180348.png">

これで再度デプロイします。

<img width="1173" alt="スクリーンショット 2015-12-22 14.38.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/afd4e2ad-e353-53f1-92b0-f53193bb3be0.png">

そして再度パラメータ付きでアクセスしてみますと（今回の例ですと https://node-red-123.herokuapp.com/canvas?aaa=111 ）以下のようにパラメータの値がWebページ表示されます。あとは "111" を他の値に変えたりして仕組みを理解しましょう。

<img width="504" alt="スクリーンショット 2015-12-22 15.11.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/0bac7844-8278-8450-63d5-795bc4a8653b.png">

## Salesforce Canvasに表示する

さて、前置きが長くなりましたが本題です。

まず接続アプリケーションの作成ですが基本的なSalesforce Canvasの設定については[SFDC：Force.com CanvasでHerokuアプリと連携してみました](http://tyoshikawa1106.hatenablog.com/entry/2014/09/27/134254)が詳しいです。

あえて補足しますと、以下のように "キャンバスアプリケーションの URL" に作成したエンドポイント（今回の例ですと https://node-red-123.herokuapp.com/canvas ）アクセス方法を "署名付き要求（POST）" 、場所に "Visualforce ページ" を選択します。

<img width="910" alt="スクリーンショット 2015-12-22 15.22.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/7cc1808b-cae8-7c5e-644f-518f52b25e01.png">

接続アプリケーションのアクセス方法を "署名付き要求（POST）" に設定したので以下のようにNode-REDのエンドポイントもPOSTメソッドを受け付けるように変更します。

<img width="1172" alt="スクリーンショット 2015-12-22 15.28.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/a0c1275f-e001-b8fa-b574-b78d0e05ac8c.png">

続いて以下のようにノードを配置してforce signed requestノードをダブルクリックして設定ダイアログを開きます。

<img width="1174" alt="スクリーンショット 2015-12-22 15.35.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/4c123124-be0f-5ca8-50f3-2fe43998256a.png">

ここでSalesforceと接続する情報を設定するために以下のようにペンマークのアイコンをクリックします。

<img width="1173" alt="スクリーンショット 2015-12-22 15.38.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/5adde7e8-c7f8-7003-86b5-739b9ce29f70.png">

以下のように "Login Type" は "login By Signed-Request" を選択して "User Name" に組織のユーザ名と "Client Secret" に接続アプリケーションの "コンシューマの秘密" を入力して "Add" ボタンをクリックします。

<img width="1174" alt="スクリーンショット 2015-12-22 15.43.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/f7338b46-d2ed-07a4-b1d2-52d552a42c6f.png">

ちなみに、ここで設定した組織のユーザ名は単なる目印なので以下のようにメールアドレス形式でもないものでも構いません。これで "OK" ボタンをクリックしてして設定ダイアログを閉じて "Deploy" ボタンをクリックしてデプロイします。

<img width="1174" alt="スクリーンショット 2015-12-22 15.50.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/ebcb09e1-aa29-068e-800a-2f88810f9ede.png">

最後にVisualforceページを用意します。詳しく説明しませんが接続アプリケーションが "test" という名前の場合は以下のような感じです。

```html
<apex:page >
  <apex:canvasApp developerName="test"  />
</apex:page>
```

<img width="917" alt="スクリーンショット 2015-12-22 15.53.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/24156823-d1fd-9920-f5b9-73d79072266e.png">

これでプレビューを見てみましょう。以下のようにSalesforceから送られてきたSigned Requestが検証&デコードされてコンテキストがJSONとなって画面とNode-REDのデバッグに表示されればOKです。

<img width="1174" alt="スクリーンショット 2015-12-22 15.56.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/d60f26b6-d9fb-db29-7637-3f32430c62ad.png">

<img width="1173" alt="スクリーンショット 2015-12-22 16.03.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/5c54b742-20ae-10e6-9cf6-c3b5286169e7.png">

## Salesforceのデータを取得して画面にリスト表示する

これでSalesforce CanvasのSigned Requestでの認証はうまくいったので、このままNode-REDでSalesforce側のデータを取得してTemplateノードで表示してみましょう。

まずは以下のようにChangeノードを配置します。

<img width="1174" alt="スクリーンショット 2015-12-22 16.09.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/ed37a3e7-82fd-672b-4c80-e4affa0d4221.png">

配置したChangeノードの設定ダイアログを開き（Changeノードをダブルクリック）以下のように`msg.payload`へ`Select Id, Name From Account`というSOQL文字列をセットするように定義します。

<img width="1175" alt="スクリーンショット 2015-12-22 16.12.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/80fe1933-bdc0-dda1-a01e-4a63d36a330d.png">

続いて以下のようにforceノードを配置します。

<img width="1176" alt="スクリーンショット 2015-12-22 16.21.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/db0481a9-1419-3a9a-0484-21ddec8ada49.png">

配置したforceノードの設定ダイアログを開き（forceノードをダブルクリック）以下のように "Log in as" は先ほどforce signed requestノードで設定したアカウントと同じアカウントを選択、 "Operation" は "query" を選択してデプロイします。

<img width="1173" alt="スクリーンショット 2015-12-22 16.17.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/9d82130c-f88b-a2d4-7cbf-041e4d475023.png">

これでSalesforceからデータ取得できるか一旦試してみます。再度、先ほど作成したVisualforceページへアクセスします。以下のようにJSONでAccountの情報が表示されればOKです。

<img width="1175" alt="スクリーンショット 2015-12-22 16.24.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/622cc984-1a96-a8d0-f03c-1218e74a3037.png">

これはChangeノードでSOQLを`msg.payload`にセットして流すことで、後続のforceノードが受け取ったSOQLを実行してデータを取得しているという流れです。

Node-REDでは前段のノードから後続ノードのパラメータを流して、後続の動作を動的にするテクニックをよく使います。これによって冗長なデータフローになるのを避けられます。

最後にTemplateノードを以下のように配置して...

<img width="1174" alt="スクリーンショット 2015-12-22 16.26.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/ad5cc1ea-cfac-c899-9915-7afd1022f7c6.png">

以下のように定義してデプロイして...

```html
<ul>{{#payload.records}}<li>{{Id}} : {{Name}}</li>{{/payload.records}}</ul>
```

<img width="1174" alt="スクリーンショット 2015-12-22 16.31.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/41a71119-940e-5a68-437e-f16cc43d7b67.png">

再度、Visualforceページへアクセスして以下のように表示されたらOKです。

<img width="1172" alt="スクリーンショット 2015-12-22 16.33.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/466ac6de-97fa-3732-2fb7-722715a5e3e5.png">

## まとめ

私が思うにNode-REDはSalesforceの外の世界でもビジュアルワークフロー&データフロー的なプロトタイピングでユーザと会話しながら要件の認識を合わせていくのに適したツールだと思います。

そのような使い方を可能にするためには気軽に誰でもどこでもインストールして使えるべきです。オープンソースソフトウェアの時点で、その大半はクリアしているのですが、今後も色々と考慮して発展していかないといけない点も多々あります。

そのためには様々な領域の有志が集い、様々なユースケースにおいてNode-REDを利用するにはどうしたら使いやすいかを考え発展させなければならないと思います。また、Node-REDは発展できるポテンシャルもあります。

貢献してみたい方は是非[Node-REDユーザグループ](https://www.facebook.com/groups/noderedjp/)に参加しましょう！

## おまけ

今回の設定（Node-REDではフローと呼びます）はJSONをインポートすると再現できます。インポートのやり方は以下のようにメニューから "Import > Clipboard" を選択して開いたダイアログに以下のJSONを貼付けます。

<img width="1174" alt="スクリーンショット 2015-12-22 16.36.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/21109/f80594a8-91a5-52e2-d8a5-80e90a0c75a7.png">


```json
[{
	"id": "4f9b24d7.b064dc",
	"type": "force",
	"z": "",
	"username": "",
	"loginurl": "https://login.salesforce.com",
	"logintype": "Signed-Request"
}, {
	"id": "68be3f5.f9741c",
	"type": "debug",
	"z": "569fcd48.a96034",
	"name": "",
	"active": true,
	"console": "false",
	"complete": "false",
	"x": 513,
	"y": 222,
	"wires": []
}, {
	"id": "d1e76ece.2e189",
	"type": "http in",
	"z": "569fcd48.a96034",
	"name": "",
	"url": "/canvas",
	"method": "post",
	"swaggerDoc": "",
	"x": 125,
	"y": 63,
	"wires": [
		["f70ef5e8.08f108"]
	]
}, {
	"id": "f70ef5e8.08f108",
	"type": "force signed request",
	"z": "569fcd48.a96034",
	"force": "4f9b24d7.b064dc",
	"name": "",
	"x": 320,
	"y": 64,
	"wires": [
		["870ac031.78f54"]
	]
}, {
	"id": "870ac031.78f54",
	"type": "change",
	"z": "569fcd48.a96034",
	"name": "",
	"rules": [{
		"t": "set",
		"p": "payload",
		"to": "Select Id, Name From Account"
	}],
	"action": "",
	"property": "",
	"from": "",
	"to": "",
	"reg": false,
	"x": 526,
	"y": 64,
	"wires": [
		["9238e368.6dc72"]
	]
}, {
	"id": "9238e368.6dc72",
	"type": "force in",
	"z": "569fcd48.a96034",
	"force": "4f9b24d7.b064dc",
	"operation": "query",
	"sobject": "",
	"extname": "",
	"name": "",
	"x": 128,
	"y": 135,
	"wires": [
		["68be3f5.f9741c", "7612ac7f.89ed54"]
	]
}, {
	"id": "5e74439f.a18bbc",
	"type": "http response",
	"z": "569fcd48.a96034",
	"name": "",
	"x": 494,
	"y": 135,
	"wires": []
}, {
	"id": "7612ac7f.89ed54",
	"type": "template",
	"z": "569fcd48.a96034",
	"name": "",
	"field": "payload",
	"format": "handlebars",
	"template": "<ul>{{#payload.records}}<li>{{Id}} : {{Name}}</li>{{/payload.records}}</ul>",
	"x": 310,
	"y": 137,
	"wires": [
		["5e74439f.a18bbc"]
	]
}]
```