Node-REDでAPI呼び出ししてみます
ここではZohoのAPIを使ってみます。Node-REDフローからこれらのAPIを呼び出し、その結果を確認します。
#1.Zohoの認証トークンを取得します
-
https://accounts.zoho.com/apiauthtoken/nb/create?SCOPE=ZohoCRM/crmapi&EMAIL_ID=Zoho CRM Username or Email ID&PASSWORD=Your Zoho CRM Password
の形式でアクセスすると、認証トークンが得られます - EMAIL_ID: Zoho CRMのユーザー名かeメールIDを指定します
- scope: 対象スコープとして、上記のサンプルのまま「ZohoCRM/crmapi」と指定します
- PASSWORD: Zoho CRMのパスワードを指定します
認証トークンを取得
https://accounts.zoho.com/apiauthtoken/nb/create?SCOPE=ZohoCRM/crmapi&EMAIL_ID=tester@mail&PASSWORD=xxxxxxxx
#
#Wed Sep 12 08:04:22 JST 2017
AUTHTOKEN=abcdefghijklmnopqrstuvwxyz012345
RESULT=TRUE
- 上記で入手されたAUTHTOKENを使ってこのあとのAPIアクセスを行います
#2.API呼び出しします
- 以下のフローをコピペします
[{"id":"d5df6896.3e0598","type":"inject","z":"d83431e3.9f7df","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":140,"y":120,"wires":[["ea8a1264.5d5518"]]},{"id":"ea8a1264.5d5518","type":"http request","z":"d83431e3.9f7df","name":"zoho getRecords","method":"GET","ret":"txt","url":"https://crm.zoho.com/crm/private/xml/Leads/getRecords?authtoken=abcdefghijklmnopqrstuvwxyz012345&scope=crmapi","tls":"","x":340,"y":120,"wires":[["3c1c8d5.ced03f2","dc908226.415968","a00149d1.9ec6e8"]]},{"id":"dc908226.415968","type":"http response","z":"d83431e3.9f7df","name":"","statusCode":"","headers":{},"x":530,"y":120,"wires":[]},{"id":"3c1c8d5.ced03f2","type":"debug","z":"d83431e3.9f7df","name":"","active":true,"console":"false","complete":"false","x":550,"y":160,"wires":[]},{"id":"1796ffd8.0c2b78","type":"function","z":"d83431e3.9f7df","name":"stringify","func":"var m = JSON.stringify(msg.payload);\nmsg.payload.op = m;\nvar n = JSON.stringify(msg.targetattr);\nmsg.payload.targetattr = n;\nreturn msg;","outputs":1,"noerr":0,"x":380,"y":1460,"wires":[["7503d503.1a0454"]]},{"id":"7503d503.1a0454","type":"template","z":"d83431e3.9f7df","name":"グラフを表示","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE html>\n<html lang=\"ja\">\n<head>\n <meta charset=\"utf-8\">\n <title>データベースからのIoTデータ表示</title>\n <script src=\"https://d3js.org/d3.v4.min.js\"></script>\n\n <style type=\"text/css\">\n /* ここにスタイルルールを追加します */\n .axis path,\n .axis line {\n fill: none;\n stroke: black;\n shape-rendering: crispEdges;\n }\n .axis text {\n font-family: Meiryo;\n font-size: 11px;\n }\n </style>\n\n <div id=\"op\" foo={{ payload.op }}/>\n <div id=\"ta_a\" ta_b={{ payload.targetattr }}/>\n\n <script type=\"text/javascript\">\n // payload.opにdashDB検索結果を、payload.targetattrに表示対象の属性名を保持\n var ta_c = document.getElementById( 'ta_a' ).getAttribute( 'ta_b' );\t//属性名を取得\n target_attr = ta_c.substr( 1, ta_c.length-3 ); //冒頭と末尾の\"\"を削除。エラーになるので。\n\n var op_a = document.getElementById( 'op' ).getAttribute( 'foo' );\t//検索結果を取得\n op_a = op_a.substr( 0, op_a.length-1 ) ;\t//末尾の\"/\"でエラーになるので\n var op_a2 = JSON.parse(op_a);\t//JSON文字列からjavascriptオブジェクトを復元\n\n var op_a3 = new Array();\n for(var i in op_a2){\n op_a3.push(op_a2[i][target_attr]);\t//対象とする属性の値を取り出して配列op_a3に順次格納\n }\n\n var op_a5 = new Array();\n for(var i in op_a2){ // 対象エントリーの時刻を格納\n op_a5.push(op_a2[i].HOUR + \":\" + (( \"0\" + op_a2[i].MINUTE ).substr( -2 )));\n }\n\n var m = 0; // 時と分を結合して時刻を保持する\n var mh = 0; // 最大値が発生したときの時\n var mm = 0; // 最大値が発生したときの分\n var mt = 0; // 最大値\n for(var i in op_a2){\n // console.log('i = ', i, ', value = ', op_a2[i][target_attr], ', h = ', op_a2[i].HOUR, ', m = ', op_a2[i].MINUTE);\n // op_a2配列を探索して、最大値を見つける\n if (m < Number(op_a2[i][target_attr])) {\n m = Number(op_a2[i][target_attr]);\n mh = op_a2[i].HOUR;\n mm = ( \"0\" + op_a2[i].MINUTE ).substr( -2 ) ;\n mt = op_a2[i][target_attr]; // 最大値の文字列での値\n mv = parseFloat(mt, 10); // 最大値の数値での値\n //console.log(\"max found was \" + mh + \":\" + mm + \" \" + mt);\n }\n }\n\n m = mh + \":\" + mm;\n // console.log('mt = ', mt);\n // 表示する画面の幅( Width )と高さ( height )\n var w = 1000;\n // zoomの値は、最大値が100以上であればそのまま(1倍)、最大値が100より小さければ4倍、\n // 最大値が10より小さければ10倍、最大値が3より小さければ20倍に\n var zoom = ( mv < 100 ) ? (( mv < 10 ) ? (( mv < 3 ) ? 20 : 10 ) : 4 ) : 1;\n // console.log('zoom = ', zoom);\n // 画面の高さは、最大値xズーム値+50 か 100のどちらか大きいほう\n var h = Math.max(mv*zoom + 50, 100);\n // console.log('h = ', h);\n var barPadding = 1; // 棒グラフの棒と棒の間隔\n var margin = 30; // グラフ表示域のまわりの余白\n\n var dataset = op_a3; // 対象エントリーを保持\n var datasetT = op_a5; // 対象エントリーの時刻を保持\n\n // スケール関数の生成\n var xScale = d3.scaleLinear()\n .domain([0, d3.max(dataset, function(d) { return d; })])\n .range([margin, w + margin * 2]);\n\n var yScale = d3.scaleLinear()\n .domain([0, (h-margin) / zoom]) // Y軸のスケールを棒グラフと一致させる\n .range([h-margin, 0]); // Y軸表示場所\n\n // X 軸の定義\n var xAxis = d3.axisBottom()\n .scale(xScale);\n\n // Y 軸の定義\n var yAxis = d3.axisLeft(yScale);\n\n // SVG 要素の生成\n var canvas = d3.select(\"body\")\n .append(\"svg\")\n .attr(\"width\", w)\n .attr(\"height\", h);\n\n canvas.selectAll(\"rect\")\n .data(dataset)\n .enter()\n .append(\"rect\")\n .attr(\"x\", function(d, i) {\n return i * ((w-margin) / dataset.length) + margin;\n })\n .attr(\"y\", function(d) { // 負の値は絶対値で対応\n return h - (Math.abs(d) * zoom) - margin;\n })\n .attr(\"width\", (w-margin) / dataset.length - barPadding)\n .attr(\"height\", function(d) {\n return Math.abs(d) * zoom; // 負の値は絶対値で対応\n })\n .attr(\"fill\", function(d) {\n //return \"rgb(100, 100, \" + (d * 10) + \")\";\n return \"rgb(224, 194, 132)\"; // 杏色\n });\n\n canvas.selectAll(\"text\")\n .data(datasetT)\n .enter()\n .append(\"text\")\n .text(function(d) {\n return d;\n })\n .attr(\"text-anchor\", \"middle\")\n .attr(\"x\", function(d, i) {\n return i * ((w-margin) / dataset.length) + margin + ((w-margin) / dataset.length - barPadding ) / 2;\n })\n .attr(\"y\", function(d) {\n return h;\n })\n .attr(\"font-family\", \"Meiryo\")\n .attr(\"font-size\", \"11px\")\n .attr(\"fill\", \"black\");\n\n// X 軸の生成\n/*canvas.append(\"g\")\n .attr(\"class\", \"axisBottom\")\n .attr(\"transform\", \"translate(0,\" + (h - margin) + \")\")\n .call(xAxis);\n*/\n// Y 軸の生成\ncanvas.append(\"g\")\n .attr(\"class\", \"axisLeft\")\n .attr(\"transform\", \"translate(\" + margin + \",0)\")\n .call(yAxis);\n\n\nwindow.onload = function onLoad() {\n var target1 = document.getElementById(\"output1\"); // 表示対象の属性名\n target1.innerHTML = target_attr;\n var target2 = document.getElementById(\"output2\"); // 最高値の時刻\n target2.innerHTML = m;\n var target3 = document.getElementById(\"output3\"); // 最高値\n target3.innerHTML = mt; // 最大値をロード\n}\n\n</script>\n</head>\n<body>\n\n <div id=\"a-box\" style=\"background-color: #87cefa; padding: 20px; font-family: Meiryo;\">\n <h1>データベースからのIoTデータ表示</h1>\n <br />\n <p>\n データベースに保存されたIoTデータを可視化します(加速度などのマイナス値は絶対値で表示しています)\n <br />\n </p>\n </div>\n\n <div id=\"b-box\" style=\"background-color: #ecf2fe; padding: 20px; font-family: Meiryo; \">\n <div style=\"text-align:left\" id=\"output0\"></div>\n <h2>\n <span style=\"text-align:left; font-size:18pt; color:blue\" id=\"output1\"></span> 値の出力\n </h2>\n <h2>最高値の時刻</h2>\n <span style=\"text-align:left; font-size:18pt; color:blue\" id=\"output2\"></span>\n <h2>最高値 </h2>\n <span style=\"text-align:left; font-size:18pt; color:blue\" id=\"output3\"></span>\n </div>\n</body>\n</html>\n","x":580,"y":1460,"wires":[["839b4fd6.9939"]]},{"id":"839b4fd6.9939","type":"http response","z":"d83431e3.9f7df","name":"","x":810,"y":1440,"wires":[]},{"id":"915d7821.6eeb78","type":"inject","z":"d83431e3.9f7df","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":140,"y":300,"wires":[["267c56.1dcaa3aa"]]},{"id":"267c56.1dcaa3aa","type":"http request","z":"d83431e3.9f7df","name":"zoho getCVRecords","method":"GET","ret":"txt","url":"https://crm.zoho.com/crm/private/xml/Leads/getCVRecords?authtoken=abcdefghijklmnopqrstuvwxyz012345&scope=crmapi","tls":"","x":350,"y":300,"wires":[["b30c0904.5d9c","60949ab6.2d617c"]]},{"id":"60949ab6.2d617c","type":"http response","z":"d83431e3.9f7df","name":"","statusCode":"","headers":{},"x":530,"y":300,"wires":[]},{"id":"b30c0904.5d9c","type":"debug","z":"d83431e3.9f7df","name":"","active":true,"console":"false","complete":"false","x":550,"y":340,"wires":[]},{"id":"2f60c335.6685d4","type":"http in","z":"d83431e3.9f7df","name":"","url":"/test10","method":"get","upload":false,"swaggerDoc":"","x":130,"y":460,"wires":[["f8cb4042.693648"]]},{"id":"f8cb4042.693648","type":"http request","z":"d83431e3.9f7df","name":"zoho getRecords","method":"GET","ret":"txt","url":"https://crm.zoho.com/crm/private/json/Leads/getRecords?authtoken=abcdefghijklmnopqrstuvwxyz012345&scope=crmapi","tls":"","x":310,"y":460,"wires":[["376e21c4.f11b4e","97dda319.0c059"]]},{"id":"2d888f96.563bd8","type":"http response","z":"d83431e3.9f7df","name":"","statusCode":"","headers":{},"x":790,"y":460,"wires":[]},{"id":"97dda319.0c059","type":"template","z":"d83431e3.9f7df","name":"test12.htmlを返す","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE HTML>\n<html>\n <head>\n <title>Zoho Quick Dashboard</title>\n <meta charset=\"utf-8\" />\n\n<style type=\"text/css\">\n#basic {\n}\n\n.a1 {\n background-color: #98d98e;\n height: 120px;\n padding: 20px;\n}\n.b1 {\n background-color: #e4de8a;\n padding-left: 20px;\n height: 40px;\n text-align:left;\n font-size: 18pt\n}\n.c1 {\n background-color: #cee4ae;\n height: 500px;\n text-align:left;\n font-size: 18pt;\n padding: 20px;\n font-family: Meiryo;\n}\n\n.y1 {\n background-color: #e4dc8a;\n padding-left: 10px;\n height: 250px;\n}\n.z1 {\n height: 25px;\n background-color: #8f8667;\n font-size: 18px;\n text-align: center;\n}\n\n</style>\n </head>\n <body>\n\n <div id='basic'>\n\n <div class='a1'>\n <h2>Zoho Quick Dashboard</h2><br>\n Zohoに保存されたデータを可視化します\n </div>\n\n <div class='b1'>\n </div>\n\n <div class='c1'>\n <h2>\n Zohoへの問い合わせ結果!\n </h2>\n <p>\n This is the error: <font color=\"blue\">{{ payload.response.error.0.message }} </font><br>\n This is the payload: <font color=\"blue\">{{ payload }} </font> !\n </p> \n </div>\n\n <div class=\"y1\">\n 参考URL\n <ul>\n <li><a href=\"https://nodered.org/\">Node-RED</a></li>\n </ul>\n </div>\n\n <div class=\"z1\">\n\tcopyright (c) abc.com All right reserved.\n </div>\n</div>\n\n</body>\n</html>\n","x":630,"y":460,"wires":[["2d888f96.563bd8","ddb5e586.fd8cf8"]]},{"id":"a00149d1.9ec6e8","type":"xml","z":"d83431e3.9f7df","name":"","attr":"","chr":"","x":530,"y":80,"wires":[["7d636282.e74fe4","f6836ba8.b347f"]]},{"id":"7d636282.e74fe4","type":"debug","z":"d83431e3.9f7df","name":"payload 2","active":true,"console":"false","complete":"payload","x":700,"y":80,"wires":[]},{"id":"f6836ba8.b347f","type":"debug","z":"d83431e3.9f7df","name":"","active":true,"console":"false","complete":"payload.response.error.0.message","x":800,"y":120,"wires":[]},{"id":"376e21c4.f11b4e","type":"debug","z":"d83431e3.9f7df","name":"","active":true,"console":"false","complete":"false","x":490,"y":500,"wires":[]},{"id":"ddb5e586.fd8cf8","type":"debug","z":"d83431e3.9f7df","name":"","active":true,"console":"false","complete":"false","x":810,"y":500,"wires":[]},{"id":"6ab61499.7c8b04","type":"comment","z":"d83431e3.9f7df","name":"Zoho getRecords","info":"","x":130,"y":80,"wires":[]},{"id":"2d4966ac.922c62","type":"comment","z":"d83431e3.9f7df","name":"Zoho getCVRecords","info":"","x":130,"y":260,"wires":[]},{"id":"8f20b395.bd0d98","type":"comment","z":"d83431e3.9f7df","name":"htmlで返却","info":"","x":100,"y":420,"wires":[]}]
-
http://localhost:1880
でNode-RED画面を開きます -
zoho getRecords
等と記載されているhttpノードを開き、認証トークン等を正しく設定します -
画面上部の「Zoho getRecords」フローの左端の 「timestamp」と記されているInjectノード(灰色)をクリックし、ZohoからのgetRecordsの結果が返されるのを確認します
-
同様に、二つめのinjectノードをクリックして「getCVRecords」の結果が返されるのを確認します
-
ブラウザで
http://localhost:1880/test10
をアクセスし、Zohoからのデータが取得できることを確認します
#3.サンプルのAPI呼び出しを使ってみます
- ZohoCrm APIメソッド:getRecordsで紹介されているサンプルを実行してみます
- 以下のフローをコピペします
サンプルのAPI呼び出し
[{"id":"2f60c335.6685d4","type":"http in","z":"d83431e3.9f7df","name":"","url":"/test14","method":"get","upload":false,"swaggerDoc":"","x":130,"y":460,"wires":[["97dda319.0c059"]]},{"id":"2d888f96.563bd8","type":"http response","z":"d83431e3.9f7df","name":"","statusCode":"","headers":{},"x":750,"y":460,"wires":[]},{"id":"97dda319.0c059","type":"template","z":"d83431e3.9f7df","name":"test14.htmlを返す","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE HTML>\n<html>\n <head>\n <title>Zoho Quick Dashboard</title>\n <meta charset=\"utf-8\" />\n\n<style type=\"text/css\">\n#basic {\n}\n\n.a1 {\n background-color: #98d98e;\n height: 120px;\n padding: 20px;\n}\n.b1 {\n background-color: #e4de8a;\n padding-left: 20px;\n height: 40px;\n text-align:left;\n font-size: 18pt\n}\n.c1 {\n background-color: #cee4ae;\n height: 500px;\n text-align:left;\n font-size: 18pt;\n padding: 20px;\n font-family: Meiryo;\n}\n\n.y1 {\n background-color: #e4dc8a;\n padding-left: 10px;\n height: 250px;\n}\n.z1 {\n height: 25px;\n background-color: #8f8667;\n font-size: 18px;\n text-align: center;\n}\n\n</style>\n </head>\n <body>\n\n <div id='basic'>\n\n <div class='a1'>\n <h2>Zoho Quick Dashboard</h2><br>\n Zohoに保存されたデータを可視化します\n </div>\n\n <div class='b1'>\n\n <form method=\"get\" action=\"http://localhost:1880/sample1\" style=\"display: inline\">\n <button type=\"submit\" name=\"submit\" value=\"送信\" style=\"background-color:#bcbcff\" >\n <font size=\"2\">サンプル1をリクエスト</font>\n </button>\n </form>\n\n <form method=\"get\" action=\"http://localhost:1880/sample2\" style=\"display: inline\">\n <button type=\"submit\" name=\"submit\" value=\"送信\" style=\"background-color:#bcbcff\" >\n <font size=\"2\">サンプル2をリクエスト</font>\n </button>\n </form>\n\n <form method=\"get\" action=\"http://localhost:1880/sample3\" style=\"display: inline\">\n <button type=\"submit\" name=\"submit\" value=\"送信\" style=\"background-color:#bcbcff\" >\n <font size=\"2\">サンプル3をリクエスト</font>\n </button>\n </form>\n\n </div>\n\n <div class='c1'>\n <h2>\n Zohoへの問い合わせ結果!\n </h2>\n <p>\n This is the error: <font color=\"blue\">{{ payload.response.error.0.message }} </font><br>\n This is the payload: <font color=\"blue\">{{ payload }} </font> !\n </p>\n </div>\n\n <div class=\"y1\">\n 参考URL\n <ul>\n <li><a href=\"https://nodered.org/\">Node-RED</a></li>\n </ul>\n </div>\n\n <div class=\"z1\">\n\tcopyright (c) abc.com All right reserved.\n </div>\n</div>\n\n</body>\n</html>\n","x":570,"y":460,"wires":[["2d888f96.563bd8","ddb5e586.fd8cf8"]]},{"id":"ddb5e586.fd8cf8","type":"debug","z":"d83431e3.9f7df","name":"","active":true,"console":"false","complete":"false","x":770,"y":500,"wires":[]},{"id":"8f20b395.bd0d98","type":"comment","z":"d83431e3.9f7df","name":"htmlで返却","info":"","x":100,"y":420,"wires":[]},{"id":"5604a90.1600258","type":"http in","z":"d83431e3.9f7df","name":"","url":"/sample1","method":"get","upload":false,"swaggerDoc":"","x":130,"y":560,"wires":[["d134c488.e1b1c"]]},{"id":"d134c488.e1b1c","type":"http request","z":"d83431e3.9f7df","name":"サンプル1","method":"GET","ret":"txt","url":"https://crm.zoho.com/crm/private/json/Accounts/getRecords?newFormat=1&authtoken=your_auth_token_0123456789&scope=crmapi&fromIndex=20&toIndex=200&sortColumnString=Account Name&sortOrderString=desc","tls":"","x":310,"y":560,"wires":[["97dda319.0c059"]]},{"id":"9105bac0.60c83","type":"comment","z":"d83431e3.9f7df","name":"サンプルをリクエスト","info":"","x":140,"y":520,"wires":[]},{"id":"11a0caa1.cef465","type":"http in","z":"d83431e3.9f7df","name":"","url":"/sample2","method":"get","upload":false,"swaggerDoc":"","x":130,"y":600,"wires":[["b94e2890.a4c468"]]},{"id":"b94e2890.a4c468","type":"http request","z":"d83431e3.9f7df","name":"サンプル2","method":"GET","ret":"txt","url":"https://crm.zoho.com/crm/private/xml/Accounts/getRecords?newFormat=1&authtoken=your_auth_token_0123456789&scope=crmapi&lastModifiedTime=2017-09-19+06:00:00","tls":"","x":310,"y":600,"wires":[["97dda319.0c059"]]},{"id":"447171e3.06ca9","type":"http in","z":"d83431e3.9f7df","name":"","url":"/sample3","method":"get","upload":false,"swaggerDoc":"","x":130,"y":640,"wires":[["b7344333.3c1dd8"]]},{"id":"b7344333.3c1dd8","type":"http request","z":"d83431e3.9f7df","name":"サンプル3","method":"GET","ret":"txt","url":"https://crm.zoho.com/crm/private/json/Accounts/getRecords?authtoken=your_auth_token_0123456789&scope=crmapi&selectColumns=Leads(Lead+Owner,First+Name,Last+Name,Email)","tls":"","x":310,"y":640,"wires":[["97dda319.0c059"]]}]
- 「サンプル1」「サンプル2」「サンプル3」のノードをダブルクリックで開き、
your_auth_token_0123456789
の部分を自分の認証トークンで置き換えます - ブラウザを開き、「サンプル1」「サンプル2」「サンプル3」を実行して結果を確認します