Node-RED - API呼び出ししてみる

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ズーム値＋５０　か　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":[]}]

```
<img width="1441" alt="スクリーンショット 2017-09-11 23.17.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/125842/92a05896-e7df-af9a-ef83-4108e977b265.png">

- `http://localhost:1880`でNode-RED画面を開きます
- `zoho getRecords`等と記載されているhttpノードを開き、認証トークン等を正しく設定します
- 画面上部の「Zoho getRecords」フローの左端の　「timestamp」と記されているInjectノード（灰色）をクリックし、ZohoからのgetRecordsの結果が返されるのを確認します
- 同様に、二つめのinjectノードをクリックして「getCVRecords」の結果が返されるのを確認します

- ブラウザで`http://localhost:1880/test10`をアクセスし、Zohoからのデータが取得できることを確認します

<img width="923" alt="スクリーンショット 2017-09-11 23.18.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/125842/bef26672-4080-04e2-6976-1e7ba56e181d.png">

#3.サンプルのAPI呼び出しを使ってみます
- [ZohoCrm APIメソッド：getRecords](http://tips.recatnap.info/wiki/ZohoCrm_API%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%EF%BC%9AgetRecords)で紹介されているサンプルを実行してみます
- 以下のフローをコピペします

```:サンプルの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\">サンプル１をリクエスト</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\">サンプル２をリクエスト</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\">サンプル３をリクエスト</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":"サンプル１","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":"サンプル２","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":"サンプル３","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"]]}]

```

<img width="874" alt="スクリーンショット 2017-09-19 10.11.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/125842/26c46ad1-70ba-59e7-e4a6-4d4bab18ab5c.png">

- 「サンプル１」「サンプル２」「サンプル３」のノードをダブルクリックで開き、`your_auth_token_0123456789`の部分を自分の認証トークンで置き換えます
- ブラウザを開き、「サンプル１」「サンプル２」「サンプル３」を実行して結果を確認します

<img width="1666" alt="スクリーンショット 2017-09-19 10.10.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/125842/efbe34af-a467-4b32-0b98-1a53f9795b3d.png">