前回はVBAでSalesforceの環境を弄りましたが、VBAだとローカル環境なスクリプト言語なので、操作性やパフォーマンスの良さ等のネイティブな良さを活かせる一方で、ネットに繋がっている環境でいつでも、どこでも、どんな端末でも動かしたいという要件は満たせません。
そんなときにはGoggle Apps Scriptが便利です。Google Apps ScriptはGoogleのサービスを拡張できたり、Webサービス作れたりするPaaSなスクリプト言語になります。
スプレッドシート等のGoogleサービスに対するマクロみたいなことが出来たり、単体でWebサービス作ったり、簡単なcronなバッチ処理もこなすことができます。
ということで、Google Apps ScriptからSalesforceのAPIを叩いてみました。今回はOAuthのaccess_token取得まで。
Salesforceの接続アプリケーションを作成
毎度おなじみ接続アプリケーション。今回はフルアクセスとrefresh_tokenの権限を付与しました。コールバックURLはこの時点ではテキトーなもので良いです。スプレッドシートの新規作成&スクリプトエディタ立ち上げ
まずはテキトーなスプレッドシートを作成スプレッドシートを開いたら、ツールメニューからスクリプトエディタを立ち上げる
スクリプトエディタでスクリプトを作成
以下のスクリプト・テンプレートhtmlを作成します。REDIRECT_URIはこの時点ではテキトーなもので良いです。salesforce.gs
var AUTHORIZATION_URL = "https://login.salesforce.com/services/oauth2/authorize?response_type=code&client_id={client_id}&redirect_uri={redirect_uri}&state={state}";
var ACCESS_TOKEN_URL = "https://login.salesforce.com/services/oauth2/token";
var CLIENT_ID = "input your client_id";
var CLIENT_SECRET = "input your client_secret";
var REDIRECT_URI = "https://script.google.com/macros/s/********************/usercallback";
/**
* メニューの設定
*/
function onOpen() {
SpreadsheetApp.getActiveSpreadsheet().addMenu("Salesforce Utility", [
{name:"OpenDialog", functionName: "openDialog"}
]);
}
/**
* ダイアログを開く
*/
function openDialog() {
var prop = PropertiesService.getUserProperties();
var template = HtmlService.createTemplateFromFile("dialog");
var authorization_url = AUTHORIZATION_URL;
authorization_url = authorization_url.replace("{client_id}", CLIENT_ID);
authorization_url = authorization_url.replace("{redirect_uri}", encodeURIComponent(REDIRECT_URI));
authorization_url = authorization_url.replace("{state}", ScriptApp.newStateToken().withMethod("callback").withTimeout(120).createToken());
template.authorization_url = authorization_url
SpreadsheetApp.getActive().show(template.evaluate());
}
/**
* OAuthでコールバックされたcode値を元にaccess_tokenを取得・保持する。
*/
function callback(e) {
var code = e.parameter.code;
var res = UrlFetchApp.fetch(ACCESS_TOKEN_URL, {
"method" : "POST",
"payload" : {
"grant_type" : "authorization_code",
"code" : code,
"redirect_uri" : REDIRECT_URI,
"client_id" : CLIENT_ID,
"client_secret" : CLIENT_SECRET
}
});
var prop = PropertiesService.getUserProperties();
prop.setProperty("session_info", res.getContentText());
return HtmlService.createHtmlOutput("<div>windowを閉じて!!</div>");
}
dialog.html
<a href="<?= authorization_url ?>">oauth</a>
処理の流れとしては
- onOpenでスプレッドシートを開いた時に独自メニューを作成
- 独自メニューからダイアログを呼び出して(openDialog)、authorization_urlをaタグに書き出し
- authorization_urlが埋め込まれたaリンクからOAuthを実行
- コールバックURL(https://script.google.com/macros/s/***/usercallback)でauthorization_codeを受け取ってaccess_tokenを取得
- 取得したaccess_token等の情報をUserProperty(ユーザごとのセッションストレージ的なモノ)に格納
ということで今回の例のstate値はOAuth2.0のそもそもの用途であるCSRF対策と、任意の関数の自動実行という2つの意味合いを持ちます。
認可コールバック用のWebアプリケーションを作成
スクリプトエディタの[公開>ウェブアプリケーションとして導入]からGASをウェブアプリケーションとして公開します。導入ボタン押下すると、以下のようなダイアログが表示されるので、現在のウェブアプリケーションのURL(あるいは最新のコードリンクのURL)をコピー。
URLの形式が
https://script.google.com/macros/s/hogehoge/exec
になっているので、
https://script.google.com/macros/s/hogehoge/usercallback
といった形式に書き換えたURLをSalesforce接続アプリケーションのコールバックURLとして登録し、3のREDIRECT_URIも書き換えます。
スクリプトの実行
Salesforce UtilityっていうメニューからOpenDialogでダイアログを開いて、authorization_urlのリンクをクリックして、認可してコールバック先に戻ったら手動でダイアログ閉じると、UserPropertyにaccess_tokenやらrefresh_tokenやらが入ります。あとは保持したaccess_tokenを使ってAPIを呼び出したり、access_tokenがexpireしたらrefresh_tokenで再取得する、といったいつも通りの使い方になります。
Google Apps Script実装の注意点
指定したhtmlを出力したり、テンプレートになるhtmlファイルに対して変数をバインディングして動的にhtmlを出力する等は出来ますが、出力するhtml、css、JavaScriptは全てcajaというサニタイズフレームワーク的なものによってゴニョゴニョされちゃいます。結果としてJavaScriptが自由に使えなくなり、かなり不便です。具体的にはwindow.openやwindow.close等が使えなかったりタグでtarget=“_self”って書いてもtarget=“_blank”に書き換わっちゃったりします。
本当はOAuthで認可を得るために別ウィンドウを立ち上げる(window.open)や、画面遷移(location.hrefとかリンク)的なことをしたかったのですがcajaのサニタイズのため、タグのtarget=“_blank”で認可画面を立ち上げてウィンドウのクローズは手動で行うことにしました。
次回はGoogleAppsScriptから色々とAPI叩いてスプレッドシートで遊んでみたいと思います。