はーい、おむおむですー。
※2020/07/29追記
newgraduate19-rpa.hatenablog.com
出勤とテレワークが混ざってくると
生活リズムや心身のバランスが崩れてくるので
要注意ですね。抑うつ感ヤバい。
さて、前回はAWSでBlue Prismの実行環境を作りました。
newgraduate19-rpa.hatenablog.com
完全に記事の順番を間違えた感がありますが、
武士に二言はないということで
気を落とさずに続けたいと思います。
今回は、前々回の続きで、GASを完成させたいと思います。
前々回は、Event APIを利用して
GASにPOSTされてきたJSONを調理しました。
newgraduate19-rpa.hatenablog.com
今回は、抽出したメッセージを使用して
APIとして公開されたプロセスを
GASから起動するような仕組みを作ります。
SOAP Envelopeの確認
以前の記事で、プロセスの公開方法を説明しました。
newgraduate19-rpa.hatenablog.com
Blue Prismは厳格で伝統があるアプリケーションなので、
今風でチャラチャラしたREST APIなどではなく、
WSDLにキッチリと従うSOAP APIとして公開されます。
というわけで、決められた通りに
SOAP MessageのEnvelopeを作って
RRにPOSTするような仕組みを作っていきたいと思います。
SoapUIで確認すると、
Envelopeの内容は以下の通り。
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:blueprism:webservice:pokedex"> <soapenv:Header/> <soapenv:Body> <urn:Pokedex soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <Name xsi:type="xsd:string">ポケモンの名前</Name> </urn:Pokedex> </soapenv:Body> </soapenv:Envelope>
また、ヘッダーは以下の通り。
POST http://<ホスト名>:8181/ws/Pokedex HTTP/1.1 Content-Type: text/xml;charset=UTF-8 SOAPAction: "" Content-Length: 469 Authorization: Basic ユーザ名:パスワード(Base64 Encoded)
この辺を良い感じにGAS内でいじいじしていきます。
POSTする方法
GASでHTTPのPOSTを行う場合、
UrlFetchAppクラスのfetchメソッドを使用します。
developers.google.com
デフォルトはGETのようなので、
明示的にPOSTであることを記載する必要があります。
UrlFetchApp.fetch(URL, options)
上の形式で指定するので、
諸々の情報はすべてoptionsの中に入れる必要があります。
これから作っていきましょう。
payloadを作る
まず、POSTのpayload、すなわちbodyにあたる、
SOAP Envelopeを作ろうと思います。
どうやら以前は
GASでSOAP APIをいじるための機能があったようですが、
提供が終了されてしまったようです。
薄情ですね。
gsuite-developers.googleblog.com
かといって、
SOAP APIのエンドポイントからWSDLを取ってきて、
そこからEnvelopeをいちいち作るのは面倒なので、
もうベタ打ちでEnvelope=bodyの内容を作成しようと思います。
Envelopeの作成
まず、SoapUIからEnvelopeの内容をコピペして持ってきます。
そして、入力パラメータのところだけ
Slackのメッセージから抽出した
ポケモンの名前を渡すよう設定します。
var name = (ポケモンの名前); var env = '<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:blueprism:webservice:pokedex">' + '<soapenv:Header/>' + '<soapenv:Body>' + '<urn:Pokedex soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' + '<Name xsi:type="xsd:string">' + name + '</Name>' + '</urn:Pokedex>' + '</soapenv:Body>' + '</soapenv:Envelope>';
いやぁもうくそダサいですね。
いや、別にいいんですよ?
XML ServiceでEnvelopeを作っても。
developers.google.com
ただ、もう正直見づらいだけで一から作るメリットがなかったので、
こうしたほうがbetterではある、のですが、
なんかこう、うん。。。
optionsを作る
出来ないものはしょうがないです。
気を取り直して、引き続き
ダサい方法でリクエストの種類やヘッダー部分にあたる
optionsを作っていきましょう。
とはいえ、ヘッダーに関しては、SoapUIからコピペ、
というわけにはいきません。
ちょっとだけ工夫します。
まず、概形としてはこんな感じでJSON形式で指定します。
(最小限の内容です)
var options = { "method": "post", "contentType": "text/xml; charset=UTF-8", "headers": {"Authorization": "Basic (ユーザ名):(パスワード)"} };
HTTPメソッドはPOSTだよ、
POSTのデータはXML形式のテキストで
文字コードはUTF-8だよ、
このユーザ名とパスワードでBasic認証するよ、
と指定してあげます。
ただ、いくら検証用環境とはいえ、
Blue Prismのユーザ名とパスワードを
ソース内に平文で打ち込むのは嫌なので、
今回はプロパティストアを使用します。
なお、optionsはあくまでfetchメソッドで使用するパラメータであり、
実際のHTTPリクエストのヘッダーとは厳密には違います。
ので、contentTypeをcontent-typeなどにしないよう注意が必要です。
プロパティストア
プロパティストアは、GASの機能の一つで、
キーと値のペアを管理できるというものです。
使い方はこちら↓
tonari-it.com
tonari-it.com
今回は、userというキーにユーザ名、
passwordというキーにパスワードを入れます。
この子達を取り出す方法はこんな感じ↓
const prop = PropertiesService.getScriptProperties(); const user = prop.getProperty('user'); const password = prop.getProperty('password');
Base64でエンコード
取り出したユーザ名とパスワードは、
Base64でエンコしてあげる必要があります。
こちらはUtilitiesクラスの
base64Encodeメソッドで簡単に実装できます。
const prop = PropertiesService.getScriptProperties(); const user = prop.getProperty(user); const password = prop.getProperty(password); var bsc = Utilities.base64Encode(user + ':' + password);
これでバッチシです。
完成形
これまでの記事も踏まえ、最終的に
完成したのがこちらになります☆(○分クッキング風)↓
function doPost(e) { // Slackの投稿メッセージ取得 var params = JSON.parse(e.postData.getDataAsString()); var msg = params.event.text; // プロパティストアから取得 const prop = PropertiesService.getScriptProperties(); const user = prop.getProperty('user'); const password = prop.getProperty('password'); // Base64にエンコード var bsc = Utilities.base64Encode(user + ':' + password); // 正規表現作成 const reg = new RegExp('<' + '.*?' + '>', 'g'); // 正規表現にマッチした箇所と、残った箇所のトリム var name = msg.replace(reg, '').trim(); // SOAP Envelope作成 var env = '<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:blueprism:webservice:pokedex">' + '<soapenv:Header/>' + '<soapenv:Body>' + '<urn:Pokedex soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' + '<Name xsi:type="xsd:string">' + name + '</Name>' + '</urn:Pokedex>' + '</soapenv:Body>' + '</soapenv:Envelope>'; // options作成 var options = { "method": "post", "contentType": "text/xml; charset=UTF-8", "headers": {"Authorization": 'Basic ' + bsc}, "payload": env }; // POST UrlFetchApp.fetch('http://<EC2のIPアドレス>:8181/ws/Pokedex', options); }
次回、最終回!
まとめ
・GASはSOAP APIをスコープに入れていない薄情者
・お高めの焼肉を食べたら元気になりました☆
やりたいことはいっぱい、
時間と体力が足りない(´;ω;`)