Node.js + Express で作ったアプリケーションに Node-RED を組み込んでみた話

先日、Node.js + Express で作ったアプリケーションに Node-RED を組み込む機会がありましたので、その方法を紹介したいと思います。
Node-RED を触ったのは今回が初めてだったのですが、簡単に組み込むことができました。

また、せっかく組み込むことができたので、Node-RED を使って簡単な REST API を作成してみます。

## バージョン
Ubuntu 22.04.3 LTS の中に全てをインストールしました。

- Ubuntu `22.04.3 LTS` ※WSL2 を使用
  - Node.js `18.18.0`
  - Npm `9.6.7`
  - PostgreSQL `14.10`
  - Node-RED `3.1.3`
  - node-red-contrib-postgresql `0.14.0`
  - Express `4.18.2`

## Node-RED を組み込む

まず最初に、`Node-RED` をインストールします。

```bash
npm install node-red
```

次に、Node-RED 日本ユーザ会のサイトで（ミニマムな構成の）ソースコードが掲載されているので、このソースコードを既存の Express アプリケーションに入れ込んでいきます。

[既存アプリケーションへの組込み : Node-RED日本ユーザ会 (nodered.jp)](https://nodered.jp/docs/user-guide/runtime/embedding)

今回は、`main.js` という空のファイルを作成し、`main.js` に掲載されているソースコードを丸々コピーして、進めていきます。
`main.js` にコピーしたら、1か所だけ変更を行います。
ソースコード中の`userDir:"/home/nol/.nodered/"` となっている箇所を、自分の環境の任意のディレクトリに変更しておきます。

```javascript:ソースコードの18行目辺り
userDir:"/home/nol/.nodered/"
```

変更が終わったら、アプリケーションを起動します。

```bash
node main.js
```

アプリケーションを起動したら、ブラウザで `http://localhost:8000/red` にアクセスします。
"Node-RED へようこそ！"の表示を確認できたら、無事に組み込み完了となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/4cea3b7b-b4cd-4709-a2e5-6addcb94e4ad.png)

ソースコード中に `httpAdminRoot:"/red"` と記載しているため、`http://localhost:8000/red` でアクセスします。
例えば、`httpAdminRoot:"/node"` と記載した場合は `http://localhost:8000/node` でアクセスします。 

## データベースとテーブルの作成

API を作り始める前に、データベースとテーブルを作成しておきます。
今回は `hoge` というデータベースを作成し、`hoge` ユーザで `users` テーブルを作成しました。

```sql
CREATE TABLE users (id integer, name varchar(20));
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/6bd6a1b5-5f1e-dbf7-e5a8-c43b57d55d10.png)

ついでに、テストデータも登録しておきます。

```sql
INSERT INTO users(id,name) VALUES(1,'taro');
INSERT INTO users(id,name) VALUES(2,'hanako');
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/6abf8803-0697-10b2-1a5e-c09037c277a3.png)

Node-RED でフローを作り始める前に、PostgreSQL と接続を行うための準備をしておきます。

Node-RED 画面右上のハンバーガーメニューから「パレットの管理」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/d5c5192e-44ed-a339-63e7-57eeb9fdedd7.png)

「ノードを追加」タブを選択して、"ノードを検索"と表示されている入力ボックスに **node-red-contrib-postgresql** と入力します。
結果が表示されたら「ノードを追加」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/7db5dfde-21eb-bdbf-9745-660b151b4d86.png)

ダイアログが表示されたら「追加」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/b305fc28-12b0-6413-5213-a3486250ea15.png)

しばらく待つと完了ダイアログが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/b5204dbd-4842-9ef8-f25e-37342e231cda.png)

完了ダイアログが表示されたら「現在のノード」タブを選択して、**node-red-contrib-postgresql** が表示されていることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/715c503c-9c5d-a09a-c2a5-e7055bff9994.png)

これで準備は完了です。

## API作成

今回は次のような API を作成します。

ソースコード中に `httpNodeRoot: "/api"` と記載しているため、`http://localhost:8000/api/xxx` でのアクセスとなります。

- (1) GET ※全件取得
  - http://localhost:8000/api/users
- (2) GET ※1件取得
  - http://localhost:8000/api/users/:id
- (3) POST
  - http://localhost:8000/api/users
- (4) PUT
  - http://localhost:8000/api/users/:id
- (5) DELETE
  - http://localhost:8000/api/users/:id

最初に「(1) GET ※全件取得」のフローから作成していきます。

画面左側のメニューにある「ネットワーク」の中から「http in」を選択して、フローエリアにドラッグ＆ドロップして配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/20593c34-c243-955d-8b89-ecf9b52ad7db.png)

配置した「http in」をダブルクリックして編集画面を開き、次のように入力します。入力が終わったら「完了」ボタンを押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/e2031846-e8b1-6dfe-652d-9173a12f4789.png)

次に、画面左側のメニューにある「機能」の中から「function」を選択して、フローエリアにドラッグ＆ドロップして配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/c9c5d890-9731-1964-cbee-3211acbc717c.png)

配置した「function」をダブルクリックして編集画面を開き、次のように入力します。入力が終わったら「完了」ボタンを押下します。
`msg.payload` に実行したい SQL を記述しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/cbf2927e-8e9a-b2c9-7991-31562ca05dc6.png)

次に、画面左側のメニューにある「ストレージ」の中から「postgresql」を選択して、フローエリアにドラッグ＆ドロップして配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/d8a75d44-1e65-4cfb-11b6-f01321d8cebe.png)

配置した「postgresql」をダブルクリックして編集画面を開き、次のように入力します。入力が終わったら「完了」ボタンを押下します。
あらかじめ作成しておいたデータベースの情報を入力しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/83d3154f-5aa0-14a6-a17a-605975713922.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/2f2982ce-2de6-ab99-7a6c-532b5e92204b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/7ae976d6-55a7-96c8-d567-a79a4d0e88d5.png)
「Query」は function で定義した SQL を使いたいので、mustache 記法でこのように書きます。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/923741d2-c414-e7e0-c005-0898121b997a.png)

最後に、画面左側のメニューにある「ネットワーク」の中から「http response」を選択して、フローエリアにドラッグ＆ドロップして配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/0c38d83e-78b7-464e-9894-80461e9a3402.png)

これでノードの作成は完了です。
あとは、ノードを線で繋いでいき、繋ぎ終わったら「デプロイ」ボタンを押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/971024ed-b7d1-4e2d-aabc-b8b76973f2a6.png)

デプロイに成功すると「デプロイが成功しました」メッセージが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/cf81fccf-4e43-d816-9d31-eb83a2c5fe96.png)

デプロイが成功したら、`curl`コマンドで `http://localhost:8000/api/users` にアクセスしてみます。※ブラウザでもOKです。

事前に登録しておいたテストデータが取得できました。無事に動いているようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/21809688-4974-26a4-735c-ab8c58713897.png)

残りの (2) から (5) も同じ要領でフローを作成していきます。
それぞれの function ノードに記載するコードは次のようになります。

##### ・(2) GET ※1件取得
パスパラメータで渡された `id` の値は、`msg.req.params.id` で参照可能です。
```javascript
const id = msg.req.params.id;
msg.payload = `SELECT id,name FROM users WHERE id = ${id};`
return msg;
```

##### ・(3) POST
リクエストボディで渡された`id`,`name`の値は、`msg.payload.id`,`msg.payload.name` で参照可能です。
```javascript
const {id, name} = msg.payload;
msg.payload = `INSERT INTO users(id,name) VALUES(${id}, '${name}');`
return msg;
```

##### (4) PUT
```javascript
const id = msg.req.params.id;
const name = msg.payload.name;
msg.payload = `UPDATE users SET name = '${name}' WHERE id = ${id};`
return msg;
```

##### (5) DELETE
```javascript
const id = msg.req.params.id;
msg.payload = `DELETE FROM users WHERE id = ${id};`
return msg;
```

最終的に完成したフローは次のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759747/9af6a4b4-f765-87f0-6b15-c26719f0e0c8.png)

## さいごに
Node-RED を初めて触ってみたのですが、ソースコードが公開されていたため、思っていたよりも簡単に組み込みできたように思います。

今回は、既存のアプリケーションに組み込む形で Node-RED を使用しましたが、Node-RED 単体での使用もできますので興味のある方は実際に試してみてください。
[コンテナイメージ](https://nodered.jp/docs/getting-started/local#docker%E3%81%A7%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B)があるようなので、これを使うのが一番簡単だと思います。

なお、今回は下記のサイトを参考にさせていただきました。（ほとんど、このサイトの内容をなぞった感じになっております）
https://qiita.com/noralife/items/4c9b975e9d1d664720a0