📋 Node-RED JSONノード ガイド

このガイドでは、Node-REDのJSONノードについて、初心者の方でも理解できるように詳しく説明します。

📚 1. JSONノードとは?

🤔 「JSON」って何?

JSON(JavaScript Object Notation)とは、データを「キー:値」のペアで表現するテキスト形式で、Web APIやデータ交換で広く使われています。 JSONノードは、このJSON形式の文字列とJavaScriptオブジェクトを相互変換するノードです。 日常生活で例えると、荷物に貼る伝票と中身のリストを相互変換する作業のようなものです。

📦 荷物の伝票と中身の例え:

↔️ 2つの変換方向

パース

JSON文字列 → オブジェクト

テキストデータを
プログラムで扱える形に変換

文字列化

オブジェクト → JSON文字列

データを
送信・保存用テキストに変換

📦 基本的な動作

Inject Template
(JSON文字列)
JSON Debug

JSONノードは入力データの型を自動判定します。文字列が入力されればパース、オブジェクトが入力されれば文字列化を行います。

📊 JSON文字列 → オブジェクト変換の例

入力(JSON文字列)
'{"kind":"Apple","price":100}'
↓ JSONノード(パース)↓
出力(オブジェクト)
{kind: "Apple", price: 100}

📊 オブジェクト → JSON文字列変換の例

入力(オブジェクト)
{kind: "Apple", price: 100}
↓ JSONノード(文字列化)↓
出力(JSON文字列)
'{"kind":"Apple","price":100}'

⚙️ 2. JSONノードの設定詳細

自動 動作モード

入力データの型を自動判定して変換方向を決定

文字列 → オブジェクト オブジェクト → 文字列

検証 JSONスキーマ

入力データの構造をJSONスキーマで検証

型チェック 必須項目チェック 値の範囲チェック

📋 設定項目一覧

設定項目 説明
動作 変換方向を指定(自動/常にJSON変換/常に文字列化) 自動判定がデフォルト
プロパティ 変換対象のプロパティ msg.payload
整形出力 文字列化時にインデントを付けて見やすく整形 チェックON/OFF
名前 ノードの表示名 任意の文字列

🎯 入力メッセージで制御できるプロパティ

プロパティ 説明
msg.payload 変換対象のデータ(デフォルト) JSON文字列 または オブジェクト
msg.schema 検証用のJSONスキーマ {"type":"object", "properties":{...}}

🔍 JSONスキーマによる検証

JSONノードはJSONスキーマを使って入力データの検証ができます。スキーマに合致しない場合はエラーが発生します。

// JSONスキーマの例 { "type": "object", "properties": { "kind": { "type": "string" }, "price": { "type": "number" }, "origin": { "type": "string" } }, "required": ["kind", "price"] }

📌 スキーマ検証のポイント:

🎯 3. 実用的な使用パターン

📥 サンプルフローのインポート方法:

  1. 下のサンプルフローJSONをコピー
  2. Node-REDエディタで メニュー → 読み込み を選択
  3. JSONをペーストして「読み込み」をクリック

このサンプルフローには、以下で説明する全パターンの実例が含まれています。

📋 サンプルフロー(クリックで展開)

参照元:Node-REDエディター内サンプルフロー

[ { "id": "e95345f3e4e33dbe", "type": "tab", "label": "json", "disabled": false, "info": "", "env": [] }, { "id": "9976e95d.2f8398", "type": "inject", "z": "e95345f3e4e33dbe", "name": "", "props": [{"p": "payload"}, {"p": "topic", "vt": "str"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 260, "y": 160, "wires": [["d94fc083.49d87"]] }, { "id": "6684abb1.8eb454", "type": "comment", "z": "e95345f3e4e33dbe", "name": "Example 1: Convert JSON string to JS object", "info": "", "x": 320, "y": 100, "wires": [] }, { "id": "d94fc083.49d87", "type": "template", "z": "e95345f3e4e33dbe", "name": "JSON string", "field": "payload", "fieldType": "msg", "format": "json", "syntax": "plain", "template": "{\n \"kind\": \"Apple\",\n \"price\": 100,\n \"origin\": \"Canada\"\n}", "output": "str", "x": 430, "y": 160, "wires": [["1a3dc54a.78598b"]] }, { "id": "8950a55d.023988", "type": "debug", "z": "e95345f3e4e33dbe", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 750, "y": 160, "wires": [] }, { "id": "1a3dc54a.78598b", "type": "json", "z": "e95345f3e4e33dbe", "name": "", "property": "payload", "action": "", "pretty": false, "x": 590, "y": 160, "wires": [["8950a55d.023988"]] }, { "id": "cb13761f.56c328", "type": "inject", "z": "e95345f3e4e33dbe", "name": "", "props": [{"p": "payload"}, {"p": "topic", "vt": "str"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 260, "y": 320, "wires": [["c607642a.78c3c8"]] }, { "id": "180b1e22.0074e2", "type": "comment", "z": "e95345f3e4e33dbe", "name": "Example 2: Convert JS object to JSON string", "info": "", "x": 320, "y": 260, "wires": [] }, { "id": "c607642a.78c3c8", "type": "template", "z": "e95345f3e4e33dbe", "name": "JS object", "field": "payload", "fieldType": "msg", "format": "json", "syntax": "plain", "template": "{\n \"kind\": \"Apple\",\n \"price\": 100,\n \"origin\": \"Canada\"\n}", "output": "json", "x": 420, "y": 320, "wires": [["bf309844.fa12e8"]] }, { "id": "5b6b130b.72a14c", "type": "debug", "z": "e95345f3e4e33dbe", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 750, "y": 320, "wires": [] }, { "id": "bf309844.fa12e8", "type": "json", "z": "e95345f3e4e33dbe", "name": "", "property": "payload", "action": "", "pretty": false, "x": 590, "y": 320, "wires": [["5b6b130b.72a14c"]] }, { "id": "2b18621b.e2670e", "type": "inject", "z": "e95345f3e4e33dbe", "name": "OK", "props": [{"p": "payload"}, {"p": "topic", "vt": "str"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 250, "y": 540, "wires": [["5986faee.aef954"]] }, { "id": "59acf99.9a92308", "type": "comment", "z": "e95345f3e4e33dbe", "name": "Example 3: Validate input JSON string with schema", "info": "", "x": 350, "y": 480, "wires": [] }, { "id": "5986faee.aef954", "type": "template", "z": "e95345f3e4e33dbe", "name": "JSON string", "field": "payload", "fieldType": "msg", "format": "json", "syntax": "plain", "template": "{\n \"kind\": \"Apple\",\n \"price\": 100,\n \"origin\": \"Canada\"\n}", "output": "str", "x": 430, "y": 540, "wires": [["f8a67c6d.4f1f1"]] }, { "id": "ca27c92c.ad7cb8", "type": "debug", "z": "e95345f3e4e33dbe", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 930, "y": 540, "wires": [] }, { "id": "2fad9978.ea1916", "type": "json", "z": "e95345f3e4e33dbe", "name": "", "property": "payload", "action": "", "pretty": false, "x": 770, "y": 540, "wires": [["ca27c92c.ad7cb8"]] }, { "id": "f8a67c6d.4f1f1", "type": "template", "z": "e95345f3e4e33dbe", "name": "Schema", "field": "schema", "fieldType": "msg", "format": "json", "syntax": "plain", "template": "{\n \"type\": \"object\",\n \"properties\": {\n \"kind\": { \"type\": \"string\" },\n \"price\": { \"type\": \"number\" },\n \"origin\": { \"type\": \"string\" }\n }\n}", "output": "json", "x": 610, "y": 540, "wires": [["2fad9978.ea1916"]] }, { "id": "8337e847.ac18d8", "type": "inject", "z": "e95345f3e4e33dbe", "name": "NG", "props": [{"p": "payload"}, {"p": "topic", "vt": "str"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 250, "y": 620, "wires": [["fa14d8bf.1ac938"]] }, { "id": "fa14d8bf.1ac938", "type": "template", "z": "e95345f3e4e33dbe", "name": "JSON string (invalid)", "field": "payload", "fieldType": "msg", "format": "json", "syntax": "plain", "template": "{\n \"kind\": \"Apple\",\n \"price\": \"100\",\n \"origin\": \"Canada\"\n}", "output": "str", "x": 460, "y": 620, "wires": [["f8a67c6d.4f1f1"]] } ]

パターン1: JSON文字列 → オブジェクト変換

用途: APIレスポンスやファイルから読み込んだJSON文字列をオブジェクトに変換

Inject Template
(JSON文字列)
JSON Debug

📌 動作の流れ:

  1. Templateノードで JSON文字列 '{"kind":"Apple","price":100}' を作成
  2. JSONノードが文字列を検出して自動的にパース
  3. オブジェクト {kind: "Apple", price: 100} が出力される

設定例:

動作: JSON文字列とオブジェクトの相互変換(自動) プロパティ: msg.payload 入力: '{"kind":"Apple","price":100,"origin":"Canada"}' ← 文字列(引用符付き) 出力: {kind: "Apple", price: 100, origin: "Canada"} ← オブジェクト

パターン2: オブジェクト → JSON文字列変換

用途: オブジェクトをAPI送信やファイル保存用の文字列に変換

Inject Template
(オブジェクト)
JSON Debug

設定例:

動作: JSON文字列とオブジェクトの相互変換(自動) プロパティ: msg.payload 入力: {kind: "Apple", price: 100, origin: "Canada"} ← オブジェクト 出力: '{"kind":"Apple","price":100,"origin":"Canada"}' ← 文字列

パターン3: JSONスキーマによる検証

用途: 入力データが期待する形式かどうかを検証

Inject
(OK/NG)
Template
(JSON)
Template
(Schema)
JSON Debug

📌 動作の流れ:

  1. JSON文字列とスキーマを準備
  2. JSONノードがスキーマに基づいて検証
  3. OK: オブジェクトが出力される
  4. NG: エラーが発生(Catchノードで捕捉可能)

設定例:

// スキーマ: priceは数値型を期待 { "type": "object", "properties": { "kind": { "type": "string" }, "price": { "type": "number" } } } // OK: price が数値 {"kind": "Apple", "price": 100} → 検証成功 // NG: price が文字列 {"kind": "Apple", "price": "100"} → 検証エラー

パターン4: 整形出力(Pretty Print)

用途: デバッグやログ出力用に見やすく整形

Inject Template
(オブジェクト)
JSON
(整形ON)
Debug

設定例:

整形出力: ON 入力: {kind: "Apple", price: 100, origin: "Canada"} 出力: '{ "kind": "Apple", "price": 100, "origin": "Canada" }'

パターン5: HTTP通信との組み合わせ

用途: Web APIとのJSON形式でのデータ交換

HTTP Request JSON Function
(データ処理)
Debug

設定例:

// HTTP Requestノードからの応答がJSON文字列の場合 // JSONノードでオブジェクトに変換してから処理 // HTTP Response例: '{"status":"success","data":{"temperature":25.5}}' // JSONノード出力: {status: "success", data: {temperature: 25.5}} // Functionノードでデータを取り出す: msg.payload = msg.payload.data.temperature; // 25.5

🏋️ 4. 実践演習

演習1: 基本的なJSONパース初級

📝 課題:

センサーデータのJSON文字列をオブジェクトに変換し、温度値だけを取り出してください。

🎯 要求仕様:

📊 期待される動作:

✅ 成功の条件:

💡 ヒント

Injectノードの設定:

  • payload: タイムスタンプ(デフォルト)でOK

Templateノードの設定:

  • テンプレート: {"sensor":"A","temperature":25.5,"humidity":60}
  • 出力形式: 文字列(重要!JSONオブジェクトではなく文字列)

JSONノードの設定:

  • 動作: 自動(デフォルト)
  • プロパティ: msg.payload

Changeノードの設定:

  • msg.payload を msg.payload.temperature に設定
✅ 解答例フロー
[ { "id": "ex1_inject", "type": "inject", "name": "実行", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 110, "y": 100, "wires": [["ex1_template"]] }, { "id": "ex1_template", "type": "template", "name": "センサーJSON", "field": "payload", "fieldType": "msg", "format": "json", "syntax": "plain", "template": "{\"sensor\":\"A\",\"temperature\":25.5,\"humidity\":60}", "output": "str", "x": 270, "y": 100, "wires": [["ex1_json"]] }, { "id": "ex1_json", "type": "json", "name": "JSONパース", "property": "payload", "action": "", "pretty": false, "x": 430, "y": 100, "wires": [["ex1_change"]] }, { "id": "ex1_change", "type": "change", "name": "温度を抽出", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "payload.temperature", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 590, "y": 100, "wires": [["ex1_debug"]] }, { "id": "ex1_debug", "type": "debug", "name": "結果", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 730, "y": 100, "wires": [] } ]

演習2: オブジェクトのJSON文字列化初級

📝 課題:

オブジェクトを整形されたJSON文字列に変換してください。

🎯 要求仕様:

📊 期待される動作:

✅ 成功の条件:

💡 ヒント

Templateノードの設定:

  • テンプレート: {"name":"田中","age":30,"city":"東京"}
  • 出力形式: JSONオブジェクト(文字列ではなく)

JSONノードの設定:

  • 動作: 自動
  • 整形出力: チェックON
✅ 解答例フロー
[ { "id": "ex2_inject", "type": "inject", "name": "実行", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 110, "y": 100, "wires": [["ex2_template"]] }, { "id": "ex2_template", "type": "template", "name": "ユーザーデータ", "field": "payload", "fieldType": "msg", "format": "json", "syntax": "plain", "template": "{\"name\":\"田中\",\"age\":30,\"city\":\"東京\"}", "output": "json", "x": 280, "y": 100, "wires": [["ex2_json"]] }, { "id": "ex2_json", "type": "json", "name": "JSON文字列化", "property": "payload", "action": "", "pretty": true, "x": 460, "y": 100, "wires": [["ex2_debug"]] }, { "id": "ex2_debug", "type": "debug", "name": "結果", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 610, "y": 100, "wires": [] } ]

演習3: JSONスキーマによる検証中級

📝 課題:

注文データをJSONスキーマで検証し、エラー時にはCatchノードで捕捉してください。

🎯 要求仕様:

📊 期待される動作:

✅ 成功の条件:

💡 ヒント

Template(スキーマ)ノードの設定:

  • プロパティ: msg.schema
  • 出力形式: JSONオブジェクト
  • テンプレート: {"type":"object","properties":{"product":{"type":"string"},"quantity":{"type":"number"},"price":{"type":"number"}}}

Catchノードの設定:

  • 対象: JSONノードを選択、または全てのノード

テストデータ:

  • 正常: {"product":"りんご","quantity":5,"price":150}
  • エラー: {"product":"りんご","quantity":"5個","price":150}(quantityが文字列)
✅ 解答例フロー
[ { "id": "ex3_inject_ok", "type": "inject", "name": "正常データ", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "{\"product\":\"りんご\",\"quantity\":5,\"price\":150}", "payloadType": "str", "x": 130, "y": 80, "wires": [["ex3_schema"]] }, { "id": "ex3_inject_ng", "type": "inject", "name": "エラーデータ", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "{\"product\":\"りんご\",\"quantity\":\"5個\",\"price\":150}", "payloadType": "str", "x": 130, "y": 140, "wires": [["ex3_schema"]] }, { "id": "ex3_schema", "type": "template", "name": "スキーマ設定", "field": "schema", "fieldType": "msg", "format": "json", "syntax": "plain", "template": "{\n \"type\": \"object\",\n \"properties\": {\n \"product\": {\"type\": \"string\"},\n \"quantity\": {\"type\": \"number\"},\n \"price\": {\"type\": \"number\"}\n }\n}", "output": "json", "x": 320, "y": 100, "wires": [["ex3_json"]] }, { "id": "ex3_json", "type": "json", "name": "JSON検証", "property": "payload", "action": "", "pretty": false, "x": 480, "y": 100, "wires": [["ex3_debug_ok"]] }, { "id": "ex3_debug_ok", "type": "debug", "name": "成功", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 630, "y": 100, "wires": [] }, { "id": "ex3_catch", "type": "catch", "name": "エラー捕捉", "scope": ["ex3_json"], "uncaught": false, "x": 490, "y": 160, "wires": [["ex3_debug_ng"]] }, { "id": "ex3_debug_ng", "type": "debug", "name": "エラー", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "x": 630, "y": 160, "wires": [] } ]

演習4: APIレスポンス処理上級

📝 課題:

ネストしたJSONデータをパースし、特定の値を抽出・加工してください。

🎯 要求仕様:

📊 期待される動作:

✅ 成功の条件:

💡 ヒント

Templateノードの設定:

  • ネストしたJSONオブジェクトを文字列として設定
  • 出力形式: 文字列

Functionノードのコード:

  • msg.payload.data でデータ配列にアクセス
  • 必要に応じてmapで加工
// Functionノードの例 msg.payload = msg.payload.data; return msg;
✅ 解答例フロー
[ { "id": "ex4_inject", "type": "inject", "name": "実行", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 110, "y": 100, "wires": [["ex4_template"]] }, { "id": "ex4_template", "type": "template", "name": "APIレスポンス", "field": "payload", "fieldType": "msg", "format": "json", "syntax": "plain", "template": "{\n \"status\": \"ok\",\n \"timestamp\": \"2024-01-15T10:30:00Z\",\n \"data\": [\n {\"name\": \"センサーA\", \"score\": 80, \"detail\": \"正常\"},\n {\"name\": \"センサーB\", \"score\": 90, \"detail\": \"良好\"},\n {\"name\": \"センサーC\", \"score\": 75, \"detail\": \"注意\"}\n ]\n}", "output": "str", "x": 280, "y": 100, "wires": [["ex4_json"]] }, { "id": "ex4_json", "type": "json", "name": "JSONパース", "property": "payload", "action": "", "pretty": false, "x": 440, "y": 100, "wires": [["ex4_function"]] }, { "id": "ex4_function", "type": "function", "name": "データ抽出", "func": "// data配列から名前とスコアのみ抽出\nmsg.payload = msg.payload.data.map(item => ({\n name: item.name,\n score: item.score\n}));\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 600, "y": 100, "wires": [["ex4_debug"]] }, { "id": "ex4_debug", "type": "debug", "name": "結果", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 750, "y": 100, "wires": [] } ]

🎓 5. まとめ

JSONノードの重要ポイント

⚠️ よくある間違い

📚 次のステップ

JSONノードをマスターしたら、以下のノードも学んでみましょう:

🔧 6. トラブルシューティング

よくある問題と解決方法

問題 原因 解決方法
パースエラー 不正なJSON構文 JSONバリデータで構文チェック
変換されない 既にオブジェクト/文字列 入力データの型を確認(typeof)
スキーマ検証エラー データがスキーマに不一致 スキーマ定義とデータの型を確認
文字化け 文字コードの問題 UTF-8で統一
プロパティが見つからない パス指定ミス Debugノードで構造を確認
undefined が出力 存在しないプロパティへのアクセス オプショナルチェーン(?.)を使用

💡 7. 実務での活用例

ケース1: REST APIとの通信

HTTP Requestノード(APIコール) ↓ JSONノード(レスポンスをパース) ↓ Changeノード(必要なデータを抽出) ↓ 処理... 用途: 外部サービスのAPIからデータを取得して処理

ケース2: MQTTメッセージの処理

MQTT Inノード(センサーデータ受信) ↓ JSONノード(JSON文字列をパース) ↓ Switchノード(条件分岐) ↓ 各種処理... 用途: IoTセンサーからのJSONメッセージを処理

ケース3: ファイル入出力

File Inノード(設定ファイル読み込み) ↓ JSONノード(パース) ↓ 設定値を使用... ↓ JSONノード(文字列化、整形ON) ↓ File Outノード(保存) 用途: JSON形式の設定ファイルの読み書き

ケース4: データ検証ゲートウェイ

HTTP Inノード(外部からのリクエスト) ↓ Templateノード(スキーマ設定) ↓ JSONノード(スキーマ検証付きパース) ↓ ↘ 成功 Catchノード → エラーレスポンス ↓ ビジネスロジック処理 用途: 入力データのバリデーション

🔗 8. 追加リソース


このガイドが役に立ちましたら、実際のプロジェクトで練習してみてください!
JSONノードはAPI連携の基本ツールです。

参照元:Node-REDエディター内サンプルフロー

🏠