メリークリスマス!!!(まだです)
この記事はenebular Advent Calendar 2019の5日目の記事です。
はじめに
enebularをバックエンドとして使うとき、みなさんどんな実装されてますか?
例えば状態保持だとかデータ保存とかしたくなったとき、enebularではfileのようなファイルシステムが扱えないかわりに、firebaseや/tmp上のsqliteが使えたりしますよね。
でもfirebaseは別サービスなのでgoogle側での設定が別途必要だったり、sqliteだったらSQL文の知識が必要だったりして、さくっと状態保持の実装ができる方法ってあまりないのでは? と思ってます。
そこで「Cacheノード」を使うことで、簡単な状態保持であればすぐに実現する方法がありますが、実際に使ってそうな人をあまり見かけなかったので書いてみました。
インストール
adminタブにてnode-red-contrib-cacheをインストールします。
Cache inノード、およびCache outノードがインストールされます。
基本的な使い方
Cacheノードは、簡易的なKey-Value形式のデータストアとして利用することができます。
以下のようなフローを組んでみましょう。
こちらのフローは2つのノードチェーンを持っており、
上がCache outを利用したキャッシュ内の特定のKeyへのValue書き込み、
下がCache inを利用したキャッシュ内の特定KeyからのValue読み出しを実現するものです。
Topicの指定
Cache inノードとCache outノードの両方に関して、ノードに入力するメッセージにはキーを示す文字列を設定する必要があります。ここではfunctionノードを利用して、msg.topic = "count"を指定しています。
これが指定されたメッセージをCache outに入れるとcountトピックに対する書き込み、
Cache inに入れるとcountトピックからの読み出し、という操作になります。
キーを示す文字列を格納するメッセージ要素.topicは、以下のキャッシュノードの各設定から変更できます。
*Cache inは「キャッシュへの入力(書き込み)」、Cache outは「キャッシュからの出力(読み出し)」です。
キャッシュへ書き込み(Cache in)
Cache inノードは入力しかありません。
設定項目は以下のようになっています。
- 名前
- キャッシュの指定(後述)
- キープロパティ:キー名はmsgのどの要素に格納されているか
- バリュープロパティ:キーに対する値はmsgのどの要素に格納されているか
- TTL:ここで指定したmsgの要素内に数値が含まれていれば、デプロイ後その秒数を超えるとキャッシュがクリアされる
設定2つ目の「キャッシュの指定」は「データベースの指定」のようなもので、鉛筆マークから新たにキャッシュ追加することができます。といっても設定項目は名前ぐらいで、いくつでも作成することができます。
Default TTLは、指定しておくとデプロイ後この秒数がたつとキャッシュが自動でクリアされます。
Check Intervalはよくわかんないです。誰か教えてください。
キャッシュから読み出し(Cache out)
Cache outノードは入出力の両方を備えています。
msg.topic(設定で変更可)に読み出したいキー名を指定して入力すると、msg.payload(設定で変更可)にキー名に対応した値が格納された状態で出力されます。
設定項目は以下のようになっています。
- 名前
- キャッシュの設定:既存のキャッシュを選択or新規で作成もできる
- キープロパティ:読み出したいキー名がmsgのどの要素に格納されているか
- バリュープロパティ:読み出した値をどこに格納したいか
- Use string payload:文字列のペイロードを利用?(詳細不明)
- Route to the second...:出力を2系統にし、通常時は1つめの出力ポートのみに値を出力し、キーに対応する値がもうない(null)ときは2つめの出力ポートのみにnull値を出力する
使ってみる
デプロイしたら、まず上側のinjectをクリックしてみましょう。するとCacheの各ノードの下に「1」と表示が出て、データが1つだけストアされたことが確認できます。
そのあとで下側のinjectをクリックすると、先ほどストアされたtimestampがデバッグノードに出力され、デバッグタブに表示されることが確認できます。
バックエンドとしての利用例
injectをそれぞれhttpに置き換え、各ノードチェーンの末尾にhttp responseを付加するだけで、特定のURLをGETしたときのパラメータ、あるいは特定のURLに対してPOSTしたJSONを、別のURLから参照することができます。
応用例
いくつか応用例を示します。
フローは公開しておきますので、興味ある方はインポートしてご利用ください。
https://enebular.com/discover/flow/3d0dd2a4-8c92-413d-a6a4-319fb57e5660
おそらく、インポート後にエディタを開くと、Cacheノードがインストールされておらずエラーが出るかと思います。
このような場合はそのままadminタブを開いてnode-red-contrib-cacheをインストールしてください。
「Installing...」という表示が出て、インストールが完了すればそのままブラウザをリロードしてください。
いつまでもインストール中の表示が出ている場合は2〜3分ほど待ってからリロードするとインストールに成功している場合があります。うまくできないときは根気よく何回か試してみてください。
更新がうまくいくとこんな感じで復活します。
アクセスカウンタ
/counter にアクセスするたびに数値が増えていきます。カウンタ値を一度読み出して+1し、同じキーに上書きしています。
なんだかちょっと懐かしい感じですね!
JSONをストアしてくれる簡易アップローダ的なもの
/storeにapplication/jsonをPOSTすると、キャッシュ内にどんどん保存してくれます。
/getにindexパラメータつきでアクセスすると、そのindexに対応する保存済みのJSONを出力してくれます。
上記フローのままだと、POST時にストア先のindexを教えてくれないことと、index=0がnullになるという欠点があるため、若干修正したほうがよいかもしれません。
LINE風の簡易チャット
1対1のチャットも簡単に作れます。
こちらのフローでは、/meを自分のエンドポイント、/youを相手のエンドポイントとして、GETパラメータのmessageに投稿したいメッセージを指定してアクセスすると某メッセージングアプリ風のチャット画面が開くようにしてみました。
フロントはtemplateノードを使ってCSSとHTMLでがっつり作ってありますが、記事の主旨と離れますので公開されているフローをインポートして直接確認してみてください。
バックエンドとしては、アクセスがあるたびに投稿されたメッセージを読み取り、キャッシュからログを読み出し、htmlタグで囲んだメッセージをログの末尾に追記し、そのログをまたキャッシュの同じ場所に保存する、という流れとなっています。
アクセスカウンタの文字列版みたいな感じですね。
まとめ
外部サービスに頼ったり、SQLのような追加知識を必要とすることなく、データの簡易保存ができました!
しかしもちろん、使っている人がほぼいないということは、良いところばかりではないということで……
利点
- enebularだけでデータ保存が実現できる
- Key-Value形式でシンプルにJSONオブジェクトが保存できる
- SQLiteのようにSQL文を直接書いたりしなくてもよい
欠点
- 「キーを示す文字列が入ったmsgの要素」を指定する必要があり、ややこしい
- デプロイしなおすと中身がすべてクリアされてしまう
- フローを再読み込みしたときにアンインストールされた状態になってしまうことがある
以上の点をふまえると、データストアが必要だけどさくっとバックエンド組みたい! なんてときに最適なのではないでしょうか。
ハッカソンのように短時間でプロトタイプを作るときなどに向いているかもしれません。
こんな感じで少しクセのあるCacheノードですが、ぜひとも活用してみてくださいね〜。