🏮
Node-RedでPOSTされたJSONをPostgreSQLへ書き込む
1. 必要なノードのインストール
PostgreSQLを操作するには、専用のコントリビュートノードが必要です。
- Node-REDエディタ右上のメニュー(≡)を開き、「パレットの管理」を選択します。
- 「ノードを追加」タブに切り替えます。
- 検索ボックスに
node-red-contrib-postgresqlと入力します。 - 表示されたノードの「インストール」ボタンをクリックし、インストールを完了します。
2. フローの作成
以下のノードをパレットからワークスペースに配置し、接続します。
-
http in: HTTPリクエストの受付 -
function: SQLクエリの生成 -
postgres: データベースへのクエリ実行 -
http response: クライアントへの応答 -
catch: エラーハンドリング -
debug: 動作確認(推奨)
フロー接続図
3. 各ノードの設定詳細
3.1. http in (リクエスト受付)
-
メソッド:
POST -
URL:
/write-db(任意のエンドポイント) -
名前:
POST /write-db
3.2. postgres (データベース接続設定)
このノードで、まずデータベースへの接続情報を設定します。
- ノードをダブルクリックし、設定画面を開きます。
- サーバー項目の右にある鉛筆アイコンをクリックします。
-
接続情報を以下のように入力します。
-
ホスト:
localhost(またはPostgreSQLサーバーのIP/ホスト名) -
ポート:
5432(デフォルト) - ユーザー: (データベースのユーザー名)
- パスワード: (上記ユーザーのパスワード)
- データベース: (接続先のデータベース名)
- 名前: (任意、接続設定の識別名)
-
ホスト:
- 必要に応じて「SSL」タブでSSL接続の設定を行います。
- 「追加」(または「更新」)ボタンをクリックして接続情報を保存します。
- ノード設定画面に戻り、「完了」をクリックします。
3.3. function (クエリ生成)
受け取ったJSONから安全なSQLクエリ(INSERT文)を生成します。
-
名前:
クエリ生成 -
コード:
// 想定する入力JSON: { "table": "sensors", "data": { "device_id": "A", "temperature": 25.4 } } const payload = msg.payload; // --- 入力値の基本チェック --- if (!payload.table || typeof payload.data !== 'object' || Object.keys(payload.data).length === 0) { throw new Error("Invalid JSON format. 'table' and 'data' object are required."); } // --- SQLインジェクション対策: テーブル名・列名の検証 --- // 英数字とアンダースコアのみを許可する正規表現 const validateIdentifier = (str) => { if (!/^[a-zA-Z0-9_]+$/.test(str)) { throw new Error(`Invalid identifier used for table/column name: ${str}`); } // ダブルクォートで囲み、予約語との衝突を避ける return `"${str}"`; }; const table = validateIdentifier(payload.table); const data = payload.data; const columns = Object.keys(data).map(col => validateIdentifier(col)); const values = Object.values(data); // --- パラメータ化クエリの生成 --- // 値のプレースホルダー($1, $2, ...)を動的に生成 const placeholders = values.map((_, i) => `$${i + 1}`).join(', '); // INSERT文を組み立てる (RETURNING * で挿入結果を取得) const query = `INSERT INTO ${table} (${columns.join(', ')}) VALUES (${placeholders}) RETURNING *;`; // postgresノードは msg.query と msg.params を参照する msg.query = query; msg.params = values; // 値はノードが安全にエスケープしてくれる return msg;
3.4. catch (エラーハンドラ)
フロー内で発生したエラーを捕捉します。
- スコープ: 「現在のフローのノード」を選択
3.5. function (成功レスポンス生成)
データベースへの書き込みが成功した際のHTTPレスポンスを作成します。
-
名前:
成功レスポンス -
コード:
// postgresノードは、INSERT...RETURNINGの結果を配列で返す const insertedData = msg.payload[0]; // 挿入された最初の行 msg.statusCode = 201; // 201 Created msg.payload = { status: "success", message: "Data successfully inserted.", inserted: insertedData }; return msg;
3.6. function (失敗レスポンス生成)
エラーが発生した際のHTTPレスポンスを作成します。catchノードから接続します。
-
名前:
失敗レスポンス -
コード:
// catchノードはエラー情報を msg.error に格納する const errorMessage = msg.error.message || "An unknown error occurred."; // エラー内容に応じてステータスコードを分ける // 400: クライアント側のリクエストが不正 // 500: サーバー側の問題 if (errorMessage.includes("Invalid JSON") || errorMessage.includes("Invalid identifier")) { msg.statusCode = 400; // Bad Request } else { msg.statusCode = 500; // Internal Server Error } msg.payload = { status: "error", message: errorMessage }; return msg;
3.7. http response
- このノードは特に設定は不要です。前のノードから渡された
msgオブジェクト(msg.payloadとmsg.statusCode)を元に自動で応答します。
4. テストコード
curl -X POST http://192.168.1.179:1880/insert \
-H "Content-Type: application/json" \
-d '{"table": "mytable", "data": {"col1": 100, "col2": 200}}'
#{"status":"success","message":"Data successfully inserted.","inserted":{"col1":100,"col2":200}}
Discussion