まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:node-red

先日このブログでも紹介した IBM watsonx.ai のベータ版 REST API を使って、Node-RED のカスタムノードを作り、公開してみました。以下で使い方を紹介しますが、実際に利用するには前回 REST API を利用する紹介をした時のブログでも作成した Watson Studuio と Watson Machine Learning を使ったプロジェクトを登録しておく必要があります(そのプロジェクトの ID が必要です)。またこれも同様に前回紹介しましたが、実行するユーザーの IBM Cloud IAM API キーを生成/取得しておく必要があるのでこちらも準備の上で試してみてください。

なお以下で紹介する内容では Node-RED v2.2.3 を使って動作確認しています。また私が提供しているものは公式のものではなく、あくまで個人的に開発したものを個人的に公開しているだけであること、現時点で提供されている REST API 自体がベータ版のため、今後近い将来の API 変更などにより動かなくなる可能性があることをご了承ください(とはいえ、私も使うので、少なくとも公式ノードが出るまではなるべくタイムリーにメンテナンスするつもりです)。


【パレットに watsonx.ai ノードを追加】
Node-RED のパレット画面を開き、右上のメニューから「パレットの管理」を選択してパレットのカスタマイズ画面に移動します。ここで「ノードを追加」タブを選び、"node-red-contrib-dotnsf-watsonxai" を検索してください(2023年7月20日時点では "watsonx" と検索すると1つだけ(!)見つかるのがそれです)。検索できたら「ノードを追加」ボタンをクリックします:
2023072001


以下のような確認ダイアログが表示されるので「追加」をクリックします:
2023072002


正しくインストールされると「ノードをパレットへ追加しました」というメッセージが表示されます。パレット管理画面を閉じます:
2023072003


元のパレット画面に戻ると、"watsonx.ai" というノードが追加されているはずです:
2023072004


【watsonx.ai ノードを使う】
では追加された watsonx.ai ノードを使ってみます。watsonx.ai ノードの前後に適当なノードを追加します。以下ではシンプルで分かりやすい代表として、inject ノードと debug ノードで挟んでみました:
2023072005



watsonx.ai ノードにデータを渡すノード(上図では inject ノード)からは、msg.payload にいわゆる「プロンプト」のテキストを指定します。watsonx.ai ノードは自分に送られてきたデータの msg.payload にプロンプト指定がされている前提でそのテキスト内容に書かれた指示の返答テキストを生成します。

以下の例では msg.payload の内容を(前回のブログで紹介した内容に合わせて)以下のようにしてみました:
入力:\nAbout Watson Discovery\\nIBM Watson® Discovery is an intelligent document processing engine that helps you to gain insights from complex business documents.\n翻訳\n

2023072006


入力内容が英語で書かれていて、最後に「翻訳(してね)」と指示している内容です。watsonx.ai ノードの手前のノード(inject ノード)の設定内容は以上です。

次に watsonx.ai ノード自体にも設定が必要です。watsonx.ai ノードをダブルクリックしてプロパティ設定画面を開き、API Key と Project ID をそれぞれ入力します:
2023072007


このうち API Key は IBM Cloud の IAM API キーの値で、Project ID は Watson Studio と Watson Machine Learning で作成したプロジェクトの ID です。これらも前回のブログで紹介したものと同じ内容の問い合わせを行うサンプルなので、この作業について詳しくはこちらも参照してください。


全ての設定が完了したら作成したフローを「デプロイ」します:
2023072008


デプロイ後に inject ノード左のボタンをクリックしてメッセージを送信すると、watsonx.ai ノードが API キー、プロジェクト ID 、そしてプロンプトテキスト内容を元に問い合わせを行い、その結果が画面右のデバッグ画面内に表示されます:
2023072009


私が 2023 年7月20日に試した際の結果は "Watson Discoveryはビジネスドキュメントに関する意見を得るための知能型ドキュメント処理エンジンです。" と表示されました。上述の英語文章を翻訳してほしい、というプロンプトだったので、質問意図を正しく理解して実行できているようでした。


(いずれにせよベータ版 API を使うことになりますが)REST API を直接実行することでカスタムアプリケーションを作ることもできますが、今回紹介した Node-RED のカスタムノードを使うことで、より手軽に watsonx.ai のテキスト生成機能を体験できるようになったのではないかと思っています。


IBM Cloud から提供されている 30 日間無料 Kubernetes サービスIBM Kubernetes Service 、以下 "IKS")環境を使って利用することのできるコンテナイメージを1日に1個ずつ 30 日間連続で紹介していきます。

環境のセットアップや制約事項については Day0 のこちらの記事を参照してください。

本日 Day 19 からはプログラミング・開発系コンテナとその GUI ツールを中心に紹介します。シリーズ初回となる Day 19 はローコード開発の雄 Node-RED イメージをデプロイする例を紹介します。
Node-red-icon



【イメージの概要】
多くのノーコード/ローコード開発環境が世に出ていますが、私の理解の中では最も広く使われている環境が Node-RED であると思っています。「ノード」と呼ばれるブロックを組み合わせてデータのフローを定義するだけで、その定義通りに動きだす、という視覚的にも理解しやすい GUI プログラミングを実現しています。 HTTP だけでなく MQTT や WebSocket といった多くのプロトコルにも対応していたり、自分で独自のノートを作って活用できる特徴もあって、ローコードでありながら IoT や AI といった広い分野での応用ができる点も特徴といえます。

開発元は英 IBM の Hursley 研究所で、現在は OpenJS Foundations 管理下でオープンソース化されています。


【イメージのデプロイ】
まずはこちらのファイルを自分の PC にダウンロードしてください:
https://raw.githubusercontent.com/dotnsf/yamls_for_iks/main/nodered.yaml

今回の Node-RED も特にパラメータ指定不要で、そのままデプロイすることができます。以下のコマンドを実行する前に Day 0 の内容を参照して ibmcloud CLI ツールで IBM Cloud にログインし、クラスタに接続するまでを済ませておいてください。

そして以下のコマンドを実行します:
$ kubectl apply -f nodered.yaml

以下のコマンドで Node-RED 関連の Deployment, Service, Pod, Replicaset が1つずつ生成されたことと、サービスが 30880 番ポートで公開されていることを確認します:
$ kubectl get all

NAME                           READY   STATUS    RESTARTS   AGE
pod/nodered-5fb585f656-7bdgm   1/1     Running   0          32s

NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
service/kubernetes   ClusterIP   172.21.0.1     <none>        443/TCP          27d
service/nodered      NodePort    172.21.11.49   <none>        1880:30880/TCP   34s

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nodered   1/1     1            1           35s

NAME                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/nodered-5fb585f656   1         1         1       36s

この後に実際にサービスを利用するため、以下のコマンドでワーカーノードのパブリック IP アドレスを確認します(以下の例であれば 161.51.204.190):
$ ibmcloud ks worker ls --cluster=mycluster-free
OK
ID                                                       パブリック IP    プライベート IP   フレーバー   状態     状況    ゾーン   バージョン
kube-c3biujbf074rs3rl76t0-myclusterfr-default-000000df   169.51.204.190   10.144.185.144    free         normal   Ready   mil01    1.20.7_1543*

つまりこの時点で(上述の結果であれば)アプリケーションは http://169.51.204.190:30880/ で稼働している、ということになります。ウェブブラウザを使って、アプリケーションの URL(上述の方法で確認した URL)にアクセスしてみます:
nodered1


上図のような画面が表示され、Node-RED の作業準備ができていることがわかります。画面左のパレットメニューからノードを配置して、実際にデプロイして動かすことができます:
nodered2



【YAML ファイルの解説】
YAML ファイルはこちらを使っています:
apiVersion: v1
kind: Service
metadata:
  name: nodered
spec:
  selector:
    app: nodered
  ports:
  - port: 1880
    protocol: TCP
    targetPort: 1880
    nodePort: 30880
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nodered
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nodered
  template:
    metadata:
      labels:
        app: nodered
    spec:
      containers:
      - name: nodered
        image: nodered/node-red
        ports:
        - containerPort: 1880

Deployment 1つと、Service 1つ、環境変数の指定も不要で本シリーズで紹介する 30 個の中でも指折りにシンプルな YAML ファイルです。一応解説を加えておきます。アプリケーションそのものは 1880 番ポートで動作するように作られているため、NodePort 30880 番を指定して、外部からは 30880 番ポートでアクセスできるようにしています(NodePort として指定可能な番号の範囲は 30000 ~ 32767 です、指定しない場合は空いている番号がランダムに割り振られます)。また ReplicaSet は1つだけで作りました。


デプロイしたコンテナイメージを削除する場合はデプロイ時に使った YAML ファイルを再度使って、以下のコマンドを実行します。不要であれば削除しておきましょう:
$ kubectl delete -f nodered.yaml


【紹介したイメージ】
https://hub.docker.com/r/nodered/node-red


【紹介記録】
Dayカテゴリーデプロイ内容
0準備準備作業
1ウェブサーバーhostname
2Apache HTTP
3Nginx
4Tomcat
5Websphere Liberty
6データベースMySQL
7phpMyAdmin
8PostgreSQL
9pgAdmin4
10MongoDB
11Mongo-Express
12Redis
13RedisCommander
14ElasticSearch
15Kibana
16CouchDB
17CouchBase
18HATOYA
19プログラミングNode-RED
20Scratch
21Eclipse Orion
22Swagger Editor
23R Studio
24Jenkins
25アプリケーションFX
262048
27DOS Box
28VNC Server(Lubuntu)
29Drupal
30WordPress

このブログは Node-RED Advent Calendar 2019 に参加しています。12/22 ぶんとしてエントリーしています。


今年 2019 年に新たな試みとして挑戦したことの1つに「ボランティアで IT 勉強会を開催する」がありました。それまでにも社内外の技術者向けコミュニティで講演したり、参加した先のイベント内でゲリラ的に活動するなどは行っていました。ただ前提として IT 技術者を対象としていたり、そういった知識を持った人を対象とすることがほとんどでした。一方で IT や AI 、プログラミングが少しずつ世の中で広まっている実感もあって、そんな乖離について疑問とまでは言いませんが、より多くの人に広める活動はできないだろうか、と考えることはありました。そんな中で女性向けコミュニティや、以下で紹介する子供向け勉強会を開催させていただく機会がありました。その活動についての報告を兼ねてブログにまとめてみました。


【IT勉強会について】
この手の IT 勉強会を開催する上で会場の確保は1つの壁になります。加えてパソコンそのものは持ってきてもらうとして、その電源やプロジェクターの確保、無線 LAN の有無、机や椅子の用意、そして会場を借りる上でのコスト、加えて集客方法や会場を利用する上での制約事項等を総合的に考慮する必要があります。以下で紹介する勉強会では 2016 年に千葉県市川市にできたシェアスペース「にわにわ」をお借りして開催しました:
2019121001


簡単に説明すると無線 LAN や電源の利用可能なレンタルスペースです。トップページを見ていただくとわかるのですが、普段から地域コミュニケーションを中心とした(IT に限らない)活動をされていて、親子向けワークショップも多く開催されています(画像はトップページより)。価格も非常にリーズナブル!:
800


この会場をお借りし、今年は5月に開催したのを皮切りに計5回のIT勉強会を行いました。「IT勉強会」と銘打ってますが、基本的には IBM Cloud を使った勉強会という位置づけで、IBM Cloud コミュニティのメンバーにお手伝いをいただいています。なお(*)印がついているものは Node-RED を使ったハンズオンです:
日付タイトル内容
5/19【子連れも】BMXUG市川IT勉強会「LINEでお絵描きメッセージを送ってみよう♪」【学生も歓迎】LINE LIFF を使ったお絵描きスタンプを作る
7/13【こどもも】BMXUG市川IT勉強会「テトリスを作ってスマホで振って遊ぼう!」【おとなも】(*)IBM Watson IoT サービスを使ってゲームをリモートコントロール
8/24【こどもも】BMXUG市川IT勉強会 AI先生と外国語で会話しよう!【おとなも】IBM Watson Translator, Speech to Text, Text to Speech を使って外国語会話レッスンアプリを作る
10/19BMXUG市川IT勉強会「レースゲームを作って、鈴鹿サーキットを走ってみよう!」(*)OpenStreetMap と IBM Watson IoT サービスを使った地図ゲーム、二人協力プレイ可
12/7BMXUG 市川IT勉強会番外編 【おとなも】『スクラッチ』でゲームを作ろう!【こどもも】スクラッチを使ったおにごっこゲーム開発(コピペ一切なし)


つまり今年は5回の勉強会を開催して、そのうち2回で Node-RED を使いました。また全てのタイトルに【おとなも】【こどもも】と含まれているように、対象者の前提は設けていません。もともとこの会場で行われるイベントは両親がお子さんと一緒に参加されたり、お年寄りの方が参加されたりすることが多かったこともあって、その一環で参加していただけたら・・という思いもありました。結果的に「普段キーボード入力を使う機会が少ない(コピペして、すらそのままでは通じない)」ようなお子さんや大人の方に多く参加いただけたと思っています。この点では当初の目的がある程度達成できたと感じています。


なお勉強会ではないのですが、7/13 開催の内容については 7/18 に開催された Node-RED Con Tokyo 2019 の中でもレポートする形で紹介しています:
IBM Watson IoT を用いた遠隔ゲームコントローラーと Node-RED による簡易カスタマイズによる実現(*)


※個人的にはこれら以外でも IT 関連のボランティア活動は行っていましたが、このブログでは上記イベントに限ったレポートとさせていただきます。


【勉強会で大変だったこと】
大変だったこと、というか大変なこと。結論を最初に言うと「時間との戦い」です。

参加者は「お子さんと、その親」が大半でした。ここでの「お子さん」とは、下は小学校低学年から、上は高校生がいたかなあ・・・中学生はいました、といった感じ。おそらくスマホは僕以上に使いこなせるのでしょうが、PC を普段から使っているわけではありません。ブラインドタッチなど以ての外、「コピペ」が「Ctrl+C して Ctrl+V」と理解できるわけでもありません。「選んで、右クリックして、コピーして、・・・」と教える必要があるレベルです。PC 操作には普段の勉強会やハンズオンとは比較にならないほどの時間を要します。

加えて、全ての勉強会がハンズオン形式となっていて最終的にアプリを1つ作りあげる(!)のですが、だいたい2時間弱で作れるものを用意する必要があります。時間をかければ細かい説明もできるし、作ったものを自分の好みに合わせて改良できたりもするんですが、一方で時間が長くなって「途中で飽きられちゃう」と勉強会としては致命傷です。もうPCの前に戻ってきてくれなくなります(苦笑)。コツとしては最初にアプリのデモを見せて(つまり完成形を見せて)、ある程度興味を持ってもらって、「頑張ればあのゲームができる!」と思わせて(笑)、なんとか集中力を2時間キープしてもらう、加えて神様に祈るw! そして目的のアプリを最短コースで作り上げる!! という持久走のような2時間になります(あ、でも苦痛ではなく楽しいですw)。

勉強会で扱うハンズオンのコンテンツはベースとなるものがあったりなかったりですが、ベースがあってもこの勉強会向けの改良を行っています。理由は「そのままでは理解できない」と思われる内容があったり、キーボード入力が多すぎて着いてこれないと思われたからです。基本プログラミングなので、プログラミングの入力は必要なのですが、その内容が多すぎると集中力が途切れてしまう懸念があります。かと言ってコピペのオンパレードだと「いま自分は何をコピペしてるのか」「そもそもこれはどの部分を作っているのか」がわからず惰性の作業になってしまう(要するに勉強会にならない)恐れもあります。一方で「ある程度プログラミングっぽいことが体験できるようにしたい」とか「苦労するから完成すると嬉しい」というユーザー体験的な観点からはやっぱりプログラミングが体験できるようにもしたくて・・・ このあたりのバランスが非常に難しいのでした。実際、今も改良を続けながらコンテンツを準備しています。

コンテンツのアイデア出しやコンテンツ作りにも時間は必要だし、2時間で一通りの解説と動作確認ができるように仕上げないといけないし、毎回が色んな意味で時間との戦いになっています。


【Node-RED を使った感想】
上述のように、5回の勉強会のうち2回で Node-RED を使ったハンズオン開発を行いました。ちなみに他の2回は Node.js (のコードを github からコピーして使用)、1回は Scratch を使いました。また Node-RED を使う場合も HTML ページを記述するテンプレートノードの内容についてだけは(時間の都合もあって)コピー&ペーストで逃げました。今にして思えば Node.js の2回は Node-RED で作れるようにしておけばよかったと感じています。

プログラミング教育のハンズオンで Node-RED を使う場合のメリットは、なんといっても「少しずつ作りながら&動かしながら進めていける」ことだと思っています。ノードの説明をして、それらを組み合わせて1つのフローを作っては、作ったフローを実際に動かして動作を確認する、これを繰り返すことで機能単位で少しずつ動作を確認しながら作ろうとしているものが完成体に近づいていく様子を体験できるようになります。この「少しずつ完成に近づいていく」のがプログラミングの醍醐味であり、楽しい部分でもあると思っています。

また Node.js を使う場合と比較すると、「コマンドプロンプトやターミナルからコマンドを実行する」に相当する作業がなく、開発作業に集中できるという点も大きなメリットであると感じています。プログラミングといいつつ、最終的にサーバー上で動かすため各種 Linux コマンドを使わずに進めていくのは困難なのですが、Node-RED だとそのあたりはよく作られていて Node-RED の画面内だけでアプリを開発し、サーバー上にデプロイすることまでができます。Windows / Mac の環境依存になる部分も少ないため、教える側としては非常に楽になる、といった、副作用的な効果もありました。特に今回のように教わる側の知識があまり高くない場合では大きなメリットのあるハンズオン環境といえると思います。

似たような GUI プログラミング環境として Scratch もあります。こちらははじめからウェブサービスとして提供されている点と、画面を確認しながら作れるという点で視覚的に非常にわかりやすい環境といえます。一方で外部とのデータやりとりについてはどうしても弱い点があるようにも思えます(逆にそういうやりとりが必要なければ気にすることもないと思ってます)。この外部とのデータのやりとりについては Node-RED が得意としている分野でもあるので、このあたりが今後の使い分けの基準にもなっていくんだろうなあ、と感じています。


【今後の話】
今年の5回の勉強会を経て、比較的 IT 知識のない人(普段、ワードやエクセルさえ使う機会のないレベルの人)向けの学習環境としての Node-RED の優位性を改めて感じることができました。一応、この活動は来年以降も続けるつもりでいて、2月初旬に予定している年明け一回目のコンテンツでも使う想定をしています。

ただし、来年は「Node-RED を使う前提でコンテンツを考える」のではなく、「参加者が興味を持ちそうな(エンターテイメント性のある)コンテンツを作って」&「それを Node-RED で実現できるように改良する」という準備をしていこうと思っています。ぶっちゃけ手間がかかるといえばかかるのですが、この準備自体が自分の勉強にもなるし、そういうことが実現できる Node-RED のポテンシャルの高さを証明することにもなるのではないか、と思っています。



1つの Node-RED 環境に普通に複数人がアクセスすると同じ環境を使うことになります。これを複数人で、それぞれ個人ごとの環境で(個人ごとにフローを保存したりして)使う方法です。

Node-RED をインストールした後、通常だと以下のような node-red コマンドで Node-RED を起動します(青字は起動メッセージ)。この例だと 1880 番ポートで待ち受け状態になっています:
$ node-red

13 Feb 08:55:02 - [info]

Welcome to Node-RED
===================

13 Feb 08:55:02 - [info] Node-RED バージョン: v0.19.5
13 Feb 08:55:02 - [info] Node.js  バージョン: v6.11.2
13 Feb 08:55:02 - [info] Linux 4.4.0-121-generic x64 LE
13 Feb 08:55:03 - [info] パレットノードのロード
    :
    :
13 Feb 08:55:03 - [info] フローを開始します
13 Feb 08:55:03 - [info] フローを開始しました
13 Feb 08:55:03 - [info] サーバは http://127.0.0.1:1880/ で実行中です

この node-red コマンドにパラメータを渡して実行環境をカスタマイズすることができます。例えば以下のような settings1.js ファイルを用意します(実行ポート番号を 1881 に指定しています):
module.exports = {
  uiPort: 1881
}

更に自分のフローを保存するためのフォルダ(~/tmp/userDir1)を作っておきます:
$ mkdir -p ~/tmp/userDir1

この状態から以下のようにパラメータを指定して node-red を実行します(青字は起動メッセージ):
$ node-red -s settings1.js -u ~/tmp/userDir1

13 Feb 09:04:35 - [info]

Welcome to Node-RED
===================

13 Feb 09:04:35 - [info] Node-RED バージョン: v0.19.5
13 Feb 09:04:35 - [info] Node.js  バージョン: v6.11.2
13 Feb 09:04:35 - [info] Linux 4.4.0-121-generic x64 LE
13 Feb 09:04:35 - [info] パレットノードのロード
    :
    :
13 Feb 09:04:36 - [info] サーバは http://127.0.0.1:1881/ で実行中です
13 Feb 09:04:36 - [info] フローを開始します
13 Feb 09:04:36 - [info] フローを開始しました

今回は 1881 番ポートで Node-RED が起動しています。またここで記録したフローは ~/tmp/userDir1 内に保存されます:
2019021301


同様にして settings2.js ファイルと ~/tmp/userDir2 フォルダを作り、これらをパラメータ指定して起動すると、異なるポートで異なる記録フォルダを持つ Node-RED が(もう1つ)起動できます:
$ cat settings2.js
module.exports = {
  uiPort: 1882
}

$ mkdir -p ~/tmp/userDir2

$ node-red -s settings2.js -u userDir2
13 Feb 09:11:15 - [info]

Welcome to Node-RED
===================

13 Feb 09:11:15 - [info] Node-RED バージョン: v0.19.5
13 Feb 09:11:15 - [info] Node.js  バージョン: v6.11.2
13 Feb 09:11:15 - [info] Linux 4.4.0-121-generic x64 LE
13 Feb 09:11:15 - [info] パレットノードのロード
    :
    :
13 Feb 09:11:16 - [info] フローを開始します
13 Feb 09:11:16 - [info] フローを開始しました
13 Feb 09:11:16 - [info] サーバは http://127.0.0.1:1882/ で実行中です


フローの記録フォルダも別々に指定しているので、一方でフローを作成済みであっても他方には影響しません:
2019021302


同様にして3人以上で利用する場合もそれぞれの settingsXX.js とフロー用フォルダを作成し、それらを指定して起動することで複数人が別環境の Node-RED を使うような感じで1サーバー内の Node-RED を使うことができるようになります。まあ充分なディスクとメモリ、CPU があれば、という前提ですけど。


Node-RED の設定ファイルでカスタマイズできる内容と指定方法についてはこちらを参照ください:
https://nodered.jp/docs/configuration

なお、今回のように起動ポートとフロー保存フォルダを指定するだけであれば、settingsXX.js ファイルを用意する必要はなく、Node-RED 起動時のコマンドラインから以下のように(-p で起動ポートも)指定することができます。ただカスタマイズの範囲をどこまでにするかによっては設定ファイルを用意した方が便利だとは思っています:
$ node-red -p 1881 -u ~/tmp/userDir1






Node-RED の HTTP ノード(HTTP in ノードと HTTP Response ノード)を使うと簡単に REST API を作ることができて便利です。自分もデータベースへの CRUD 操作を作る際などによく使っています。

が、この方法で作った REST API にはクロスオリジン制約(いわゆる CORS)が付きます。例えば https://xxxx.mybluemix.net/ というホストで Node-RED を動かしている場合、作成する REST API のエンドポイント URL は https://xxxx.mybluemix.net/getdata とかになるわけですが、この API を AJAX などのブラウザ上の JavaScript から呼ぼうとすると、同一サーバー上の( https://xxxx.mybluemix.net/**** というアドレスのページの) HTML からでないとエラーになってしまうのでした。サーバーサイドのプログラムから実行することはできるのですが、ブラウザ上の JavaScript から実行するには同一ホストからでないといけない、という制約が付くのでした(ま、この制約自体はある方が一般的ですけど)。

この CORS の制約を外して、外部の(https://xxxx.mybluemix.net/ 以外の)ページやローカルシステム上ページの JavaScript からでもこの API を呼べるようにする、そのための設定方法と手順を紹介します。

まず Node-RED で REST API を作成します。今回は以下のような HTTP in ノードと、Function ノードと、HTTP Response ノードをつなげただけのシンプルな REST API を用意しました:
2018101801


HTTP in ノードの設定は以下のように GET /corstest で呼び出せるような設定にしています:
2018101802


Function ノードは以下のような JavaScript を記述し、実行時のタイムスタンプ値を JSON で返す、という関数にしています:
msg.payload = { timestamp: ( new Date() ).getTime() };
return msg;

2018101803


HTTP Response ノードにはこの段階では特に手を加えません。配置しただけの状態のまま接続してデプロイします。これで REST API 側は準備できました。

次に HTML ファイルを用意します。今回はサーバー上ではなくローカルシステム上に以下のような内容の HTML ファイルを用意しました:
<html>
<head>
<meta charset="utf8"/>
<title>CORS テスト</title>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
function corstest(){
  $.ajax({
    type: 'GET',
    url: 'http://xxxx.mybluemix.net/corstest',  // 上記で作った REST API のエンドポイントURL
    success: function( result ){
      console.log( result );
    },
    error: function( err ){
      console.log( "error" );
      console.log( err );
    }
  });
}
</script>
</head>
<body>
<input type="button" value="CORS" onClick="corstest()"/>
</body>
</html>

この HTML ファイルをブラウザから(Ctrl+O などでファイルを指定して)開くと、"CORS" と書かれたボタンが1つだけ配置されたページが開きます:
2018101807


HTML を見るとわかるのですが、このボタンをクリックすると GET https://xxxx.mybluemix.net/corstest という API が実行され、成功するとその結果が、失敗すると "error" というメッセージに続いてエラーメッセージが、それぞれ表示される内容になっています。なおこのエンドポイント URL の xxxx 部分が実際に作成した Node-RED 環境のホスト名にあわせて変更してください。


ブラウザのコンソールを開いて(F12)、この CORS ボタンをクリックします。現状は CORS の対策を何もしていないので当然のようにエラーになります。エラーの内容はコンソールに表示され、原因はクロスオリジン制約のようです。これをどうにかしたい、というのが今回のテーマです:
2018101804


では、この REST API の実行が成功するよう API 側をカスタマイズします。Node-RED のフロー画面に戻って、HTTP Response ノードをダブルクリックして編集状態にします。そして「ヘッダ」と書かれた欄の「+追加」という部分をクリックし、HTTP Response ヘッダを追加します。そして左側(ヘッダ名)の欄には Access-Control-Allow-Origin と、そして右側(ヘッダ値)の欄には *(どのドメインからのリクエストでも許可するの意)とそれぞれ入力し、最後に「完了」→「デプロイ」します:
2018101805


この設定によって REST API の実行結果を返す際のヘッダに Access-Control-Allow-Origin: * という一行が追加されて返るようになり、このヘッダによってクロスオリジンが許可されているとブラウザ側からも判断され、期待通りの結果が得られるようになります。再度 CORS ボタンをクリックして REST API を実行するとコンソールにはリクエストが成功した時の結果が表示されるようになりました:
2018101806


CORS の制約を理解した上で外す(あるいは特定のドメイン名やホスト名を指定した上で許可する)、という点に注意してください。





このページのトップヘ