以前のエントリで大学生向けのNode-RED
のハンズオンをしてきたということを書いたのですが、その時のハンズオンで2件ほど質問がでました。わりとテンパっていたので、その時はあまり良い答えを提示することができませんでした。準備していなかったというのが一番大きな理由ではありますが、さすがにそのままというのも気持ちが悪いので、このエントリに綴って置こうかと思います。
質問は以下のようなものでした。(質問文はちょっと違うかなと思いましたがこんな感じだったかと思います)
Node-RED
を使って動的なHTMLデータを作成して表示させることができるかREST API
のURIを変更することはできるのか
上記のことは、できるということはわかっていましたが、実際にあまりやっていないので試してみます。
Node-RED
を使って動的なHTMLデータを作成して表示させることができるか
ハンズオンではNode-RED
を使用してHTMLのデータを表示するという簡単なサンプルをしていました。クエリパラメータのサンプルとして、動的な表示変更は使用していましたがHTMLはほとんど使用していなかったので、そういうふうに見えなかったのかもしれません。
今回はHTMLをちゃんと(わかりやすく)使用して動的な表示変更をしてみようと思います。
静的なHTMLデータを表示する
使用するノードは以下のノードになります。
http inノード
templateノード
http responseノード
http inノード
を使用して、Webアクセスを受信し、templateノード
でHTMLデータを生成して、http responseノード
でそのHTMLデータを返送するというものになります。
これをフロー上に並べると下記の様になります。3つのノードをそのまま並べてつないだという簡単なものになります。
では、それぞれのノードのプロパティを確認していきます。
http inノード
のプロパティ
プロパティで変更しなければいけないのはメソッドとURLとなります。
今回のサンプルではWebブラウザでのアクセスを想定しているので、GETメソッド
を設定しています。また、URLはエンドポイントとなる部分なので今回は/helloworld
としています。(アクセス時はブラウザに対してNode-REDを起動しているサーバのURLのあとにこのURLパラメータをつける形でアクセスURLを表記することになります)
templateノード
のプロパティ
templateノードでは、リクエストを送信したユーザに返送するHTMLデータを作成します。 テンプレートの入力ボックスにHTML形式のテキストを入力していきます。静的なデータを表示させるのであれば通常のHTMLファイル形式で大丈夫です。
http responseノード
のプロパティ
こちらはデフォルトのままで大丈夫です。
実行結果
こちらのフローを実行し、ブラウザでアクセスを行うと、アクセスしたブラウザが以下のように表示されます。今回は静的なHTMLテキストが返送されますので、そんなに難しくはありません。
ブラウザのデベロッパーツールを使用すると、先程templateノードで入力しておいたHTML形式のデータが受信され、表示されていることがわかります。
動的な表示データをHTMLとして表示する
先程は、静的なデータになっていましたが、これを改造して動的なデータに変更してみようと思います。
今回はHTTPのリクエストを得たら、外部のREST APIへアクセスを行い、その結果をレスポンスとしてHTMLの形式で送り返すというものにします。
今回使用しているのは以下のREST APIとなります。
【参考】 project.iw3.org
郵便番号から住所情報を検索、および住所情報から郵便番号を検索を行えるREST API
追加するノードはhttp requestノード
となります。
こちらは、フロー上からHTTPのリクエストを送信できるので、HTMLの取得やREST APIへのアクセスなどをするために使用する事が多いノードになります。
こちらをフローの2番目に追加して、その内容を続くtemplateノード
に格納してHTML化してレスポンスを返します。
変更するノードのプロパティはhttp requestノード
とtemplateノード
になります。
http requestノード
のプロパティ
REST APIへのアクセスを行う機能を持ちます。プロパティ内のURL欄にREST APIへのアクセスを行うためのURLを入力します。
また、出力形式もJSONオブジェクトにすることも忘れずに行います。
templateノード
のプロパティ
先程のtemplateノード
の内容を変更します。先程までhello world
となっていた部分を以下の様に変更します。
REST APIで表示しようとしているデータは{}
で囲まれています。この記法のことをmustache記法
と呼びます。mustache
という英単語は口ひげという意味になりますが、{}
の括弧の形が口ひげの形に似ているということから、このようにいうようです。
このようにして、前段のノードから受信したデータをmustache記法
で書いていくことで、HTMLへデータを動的に入れていくことができるようになります。
このフローをデプロイして、ブラウザからアクセスを行うと以下の様に表示されます。デベロッパーツールでもREST API
の結果がHTML上に格納されているのがわかります。
フローのソースコード
[{"id":"1e264557b6c53ab9","type":"template","z":"57de3fc7e3549d4b","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html>\n<head>\n<title>Sample Page</title>\n</head>\n<body>\n{{payload.stateName}}</br>\n{{payload.city}}</br>\n{{payload.street}}</br>\n</body>\n</html>","output":"str","x":220,"y":300,"wires":[["df967681dbf8cdc7"]]},{"id":"25b6a7546553433d","type":"http in","z":"57de3fc7e3549d4b","name":"","url":"/helloworld","method":"get","upload":false,"swaggerDoc":"","x":160,"y":180,"wires":[["0d0ef7452ddd9a69"]]},{"id":"df967681dbf8cdc7","type":"http response","z":"57de3fc7e3549d4b","name":"","statusCode":"","headers":{},"x":310,"y":360,"wires":[]},{"id":"0d0ef7452ddd9a69","type":"http request","z":"57de3fc7e3549d4b","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"http://api.thni.net/jzip/X0401/JSON/460/8508.js","tls":"","persist":false,"proxy":"","authType":"","x":230,"y":240,"wires":[["1e264557b6c53ab9"]]}]
REST API
のURIを変更することはできるのか
先程の例でHTMLをREST API
を使用することで動的に変えることができるようになりました。このままではREST API
のアクセス先を変更ができていません。そのため、次の例ではHTTPのリクエストによってREST API
でのアクセス先を変更してみようと思います。
今回使用しているREST API
では郵便番号の前半3桁
と後半4桁
の2つを使用していました。この2つを指定する方法を2つ出してみます。
パラメータで指定する場合
パラメータはURLの要素として出てきたものを取り出す方法になります。
方法としてはリクエスト時のURLの場所を指定して、それをパラメータと使用するというものです。やり方は簡単で、リクエスト時のURLの特定の箇所に:〇〇
という形で埋め込むことで後続のフローで変数的に取得する事ができます。
先程のフローから赤い枠で指定した部分を変更していきます。
フロー
パラメータの設定は先程説明した通り、URLの特定の箇所に:〇〇
(コロンを忘れずに)を入れるだけです。
今回は/api/郵便番号の前半3桁/郵便番号の後半4桁
という形式でアクセスをしてもらおうと思います。http inノード
のプロパティの設定はメソッドをGET
、URLは/api/:query1/:query2
としておきます。
http inノードのプロパティ
リクエストで受けた、郵便番号を取り出してhttp requestノード
のURLに埋め込んで行きます。指定されたパラメータはmsg.req.params
の中にパラメータ名で格納されているので、それをmustache記法
で埋め込みます。
http requestノードのプロパティ
メソッドもGET
にしておくのを忘れずに。設定が完了したらデプロイをして、クライアントからブラウザでアクセスします。
(例)アクセスURL(サーバ部分は個々に違うので修正を行ってください)
実行結果
フローのソースコード
[{"id":"91514f2b09370b0e","type":"http in","z":"7caeabc7e2fd0b0d","name":"","url":"/api/:query1/:query2","method":"get","upload":false,"swaggerDoc":"","x":150,"y":240,"wires":[["6a741225e22b8501"]]},{"id":"67ae79a2ba4538aa","type":"template","z":"7caeabc7e2fd0b0d","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html>\n<head>\n<title>Sample Page</title>\n</head>\n<body>\n{{payload.stateName}}</br>\n{{payload.city}}</br>\n{{payload.street}}</br>\n</body>\n</html>","output":"str","x":300,"y":300,"wires":[["f9680de638a24949"]]},{"id":"f9680de638a24949","type":"http response","z":"7caeabc7e2fd0b0d","name":"","statusCode":"","headers":{},"x":490,"y":300,"wires":[]},{"id":"6a741225e22b8501","type":"http request","z":"7caeabc7e2fd0b0d","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"http://api.thni.net/jzip/X0401/JSON/{{{req.params.query1}}}/{{{req.params.query2}}}.js","tls":"","persist":false,"proxy":"","authType":"","credentials":{},"x":450,"y":240,"wires":[["67ae79a2ba4538aa"]]}]
クエリパラメータで指定する場合
もう一つの方法はクエリパラメータの形式で情報を引き渡します。こちらのほうが一般的かもしれません。ただ、Node-RED
のフローを見ても、クエリパラメータの指定があるように見えないというのがちょっとだけわかりにくいかなと思います。
先程まで使用していたフローを以下の様に修正していきます。
http inノード
でクエリパラメータを受け取りますが、プロパティの設定は特に必要ありません。
http inノードのプロパティ
処理を記述しませんが、アクセス時にクエリパラメータをつけておくことで自動的にノード間の通信を行うJSONに格納されます。パラメータはmsg.req.query
の中に格納されているので、それをmustache記法
で埋め込みます。
http requestノードのプロパティ
設定が完了したらデプロイをして、クライアントからブラウザでアクセスします。
(例)アクセスURL(サーバ部分は個々に違うので修正を行ってください)
実行結果
フローのソースコード
[{"id":"8467c21d2545a7c7","type":"template","z":"7caeabc7e2fd0b0d","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html>\n<head>\n<title>Sample Page</title>\n</head>\n<body>\n{{payload.stateName}}</br>\n{{payload.city}}</br>\n{{payload.street}}</br>\n</body>\n</html>","output":"str","x":300,"y":120,"wires":[["ca35503b3c8beeb4"]]},{"id":"25b6a7546553433d","type":"http in","z":"7caeabc7e2fd0b0d","name":"","url":"/api","method":"get","upload":false,"swaggerDoc":"","x":100,"y":60,"wires":[["3f1735bf6de77b35"]]},{"id":"ca35503b3c8beeb4","type":"http response","z":"7caeabc7e2fd0b0d","name":"","statusCode":"","headers":{},"x":490,"y":120,"wires":[]},{"id":"3f1735bf6de77b35","type":"http request","z":"7caeabc7e2fd0b0d","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"http://api.thni.net/jzip/X0401/JSON/{{{req.query.query1}}}/{{{req.query.query2}}}.js","tls":"","persist":false,"proxy":"","authType":"","credentials":{"user":"","password":""},"x":310,"y":60,"wires":[["8467c21d2545a7c7"]]}]
おわりに
質問が出たときにもう少しちゃんと答えられればと思ったのですが、自分でやってみると結構深い内容なのかもしれないと思いました。このぐらいの内容であれば1回位のハンズオンの内容になるのかもしれません。基本的な動きとはいえ、覚えておいて損のないないようだと思いました。