#はじめに
お金はないですがGoogleCloudPlatformのアカウントは持っているのでスプレッドシートをDBにしてWebサービスを作ってます。GASをけいゆうしてデータの読み込みから書き出しまでやろうと思ったんですが、JSから叩くのに3日かかったのでシンプルにまとめます。情報が少ない上、設定が多いのでかなりかかりました。QuickStartが全然クイックじゃないしサンプルがほんとに意地悪でした。あとは重要なことが文が多すぎて埋もれてしまってます…Googleのサポート問題は日本語化されていない時点でお察しですが、なんとか英訳してやってみました。
また、この記事は以下の記事を全面的に元にしています。
【GAS】Execution APIを使ってJavaScriptからGASにアクセスする
手順1 クライアント側
Webサイトを作ってください。URLが確定してないとだめです。サーバーレスでFirebaseHostingとかいいですよ。
あらかじめ説明しときますが制作したウェブサイトのURLの
https://example.xxx.xxx/yyyy/zzzz
https://
をスキーム、example
をサーバー名、xxx.xxx
はドメイン、example.xxx.xxx
の部分はオーソリティ、yyyy/zzzz
はパス名といいます。(諸説あるかもしれません)
手順2 GAS側
適当に新しいプロジェクトを作って関数を作ります。
function helloWebAPI(str) {
return "Hello!" + str;
}
文字列を受け取ってHello!
とくっつけるだけです。
次にGoogleCloudPlatform
との連携を行います。GASは昔は自動で連携してたんですがその機能がOFFになっているそうで自分で作らなければいけません。
手順3 GoogleCloudPlatform側
これは課金が必要です。よくわからないですが無料トライアルに銀行口座が必要らしいです。自動で請求しないみたいですが。
- 新しいプロジェクトを作る。(名前はGASと同じがわかりやすい)
-
APIとサービス
からOAuth 同意画面
に移動する。同意画面を作成していきます。 - アプリケーション名(適当)と承認済みドメインに使ってるドメインを入力し作成。(複数可)
-
APIとサービス
から認証情報
に移動する。 -
認証情報を作成
をクリック。OAuthクライアントID
を作成していきます。 - アプリケーションの種類は
ウェブアプリケーション
。名前は適当。承認済みのJavaScript生成元
はオーソリティまでを、承認済みのリダイレクトURI
はパスまで全部のURLを入れときます。(複数可)そして作成。 - 出てきた
クライアントID
の方だけを控えときます。こうゆうトークンがこれから何個か出てくるので注意です。 -
認証情報を作成
をクリック。APIキー
を作成します。すぐにできます。 - 出てきた
APIキー
を控えます。 - APIキーは制限を行わないといけないのでペンマークで編集を行い、
アプリケーションの制限
とAPI の制限
を行ってください。アプリケーションはウェブアプリケーションのみ、APIのほうはこれから使うAppsScriptAPI
のみでいいでしょう。
10のAPIの制限に関しては個人でGoogleCloudPlatform
に別のAPIを適応したりするときには他のAPIにもチェックを付けてください。自分はWindowsApplicationも作る予定があったのでアプリケーションの制限は行いませんでした。
次は外部からこれらのトークンを使って叩けるようにしましょう。
APIとサービス
からライブラリ
に移動して検索窓にGoogle Apps API
と入力して出てきたやつを有効にしてください。
ホームのダッシュボードからプロジェクト情報からプロジェクト番号
を控えましょう。
次はこのプロジェクトとGASのプロジェクトをつなげましょう。
これらの設定は以下の記事を参考にしました。現在のバージョンと違うので画面が違かったり、APIの名前が違かったりします。
【GAS】Execution APIを使ってJavaScriptからGASにアクセスする
GASのExecution APIを使ってGASを外部からぶっ叩く
ほぼ同じことをしている上、スクショつきでとてもわかりやすいです。
【GoogleAppsScript】実行可能API(Execution API)の初期設定でハマったので流れをメモする
手順4 GAS側
メニューバーからリソース
、Cloud Platform プロジェクト
を押下。プロジェクト番号
を入力して横のボタンを押して、上の方にこのスクリプトが現在関連付けられているプロジェクト:
が表示されたらオッケーです。
次はこのGASのソースコードを実行可能API
にします。
メニューバーの公開
から実行可能API
として導入を押します。バージョンを新規作成にして説明を入力。導入を押せばオッケーです。ここで出てくるAPI ID
は使いません。
さて、次は必要な情報を取得します。
メニューバーのファイル
からプロジェクトのプロパティ
を押してプロパティを見ます。
必要なのは、
- スクリプト ID
- スコープ
です。スクリプトIDは情報
タブに、スコープはスコープ
タブにあります。スクリプトIDはGASプロジェクトの判別トークンですが、スコープはこのGASプロジェクトを実行するときに許可しないといけない権限です。これらを許可していないと実行はできません。何もない人は大丈夫ですが、現在あるいは今後、スプレッドシートを見たりいじったりDriveを見たりいじったり、ほかのGoogleサービスに対して処理を行う際はこのスコープも必要になります。もちろんスコープは複数ある場合もあります。
ではいよいよクライアント側の実装に移ります。現在必要なのは以下のトークンたちです。
- クライアントID
- APIキー
- スクリプトID
- スコープ
こうゆうのってトークンいっぱいあるからいやになりますよね...
手順5 クライアント側
ファイル分ける派です。
HTML
<!DOCTYPE html>
<html>
<head>
<title>WebサイトのJSからGASの実行可能APIを最短最高で叩く</title>
</head>
<body>
<button id="authorize_button" style="display: none;">Authorize</button>
<button id="signout_button" style="display: none;">Sign Out</button>
<script async defer src="https://apis.google.com/js/api.js"
onload="this.onload=function(){};handleClientLoad()"
onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
<!-- index.jsのロード -->
</body>
</html>
APIを叩くにはユーザーにログインさせないといけないのでログインボタンを配置します。実用化のときには要らないですね。CDN(?)でapiをロードし、ロードが終わったときにhandleClientLoad()
を実行します。
JS
var CLIENT_ID = /* クライアントID */;
var API_KEY = /* APIキー */;
var SCOPES = [/* スコープリスト */];
var scriptId = /* スクリプトID */;
var DISCOVERY_DOCS = ["https://script.googleapis.com/$discovery/rest?version=v1"]; // そのまま
var authorizeButton = document.getElementById('authorize_button');
var signoutButton = document.getElementById('signout_button');
// 勝手に実行される
function handleClientLoad() {
gapi.load('client:auth2', initClient);
}
function initClient() {
// GoogleAPIのinitialize
gapi.client.init({
apiKey: API_KEY,
clientId: CLIENT_ID,
discoveryDocs: DISCOVERY_DOCS,
scope: SCOPES.join(' ')
}).then(function () {
// ログインしているかをupdateSigninStatusに渡す
updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
// ボタンが押された時の処理を代入。
authorizeButton.onclick = handleAuthClick;
signoutButton.onclick = handleSignoutClick;
}, function(error) {
appendPre(JSON.stringify(error, null, 2));
});
}
function updateSigninStatus(isSignedIn) {
if (isSignedIn) {
// ログイン済み
authorizeButton.style.display = 'none';
signoutButton.style.display = 'block';
// APIを叩く
callAppsScript("helloWebAPI", ["World!"], function(resp) {
// コールバック関数
if (resp.error) {
// エラーあり
if (resp.error.status) {
console.log('Error calling API: ' + JSON.stringify(resp, null, 2));
} else {
var error = resp.error.details[0];
console.log('Script error! Message: ' + error.errorMessage);
}
} else {
// エラーなし
appendPre(resp.response.result);
}
});
} else {
// ログインしていない
authorizeButton.style.display = 'block';
signoutButton.style.display = 'none';
}
}
// ログインボタンが押された時
function handleAuthClick(event) {
// ログインの処理
gapi.auth2.getAuthInstance().signIn();
}
// ログアウトボタンが押された時
function handleSignoutClick(event) {
// ログアウトの処理。
gapi.auth2.getAuthInstance().signOut();
}
// 画面に出力する
function appendPre(message) {
var pre = document.getElementById('content');
var textContent = document.createTextNode(message + '\n');
pre.appendChild(textContent);
}
// APIを叩く関数
function callAppsScript(functionName, parameters, callbackFunc) {
var request = { 'function': functionName, 'parameters': parameters };
var op = gapi.client.request({
'root': 'https://script.googleapis.com',
'path': 'v1/scripts/' + scriptId + ':run',
'method': 'POST',
'body': request
});
// APIを叩いてコールバック関数を呼ぶ
op.execute(callbackFunc);
}
随分と長いですがやってることはむずくないです。
handleClientLoad()
は準備が完了したときに実行されます。(HTMLに記載)initClient()
はOAuthと通信を行い、必要なすべてのスコープが許可されているか、ログインしているかを確認します。そこけっかはすぐ下の.then()
コールバックに返ってきます。結果によってログイン/アウトボタンを設定し、ログインしていればAPIを叩きます。APIを叩く際、callAppsScript()
という関数を作ってそれを実行しています。
第一引数に実行GASの関数名、第二には引数を配列で渡し、第三にはそのコールバック関数を設定してください。
実際に叩いているのはcallAppsScript()
内のop.execute()
です。リクエストJsonを制作し叩きます。resp.response.result
がreturnされた結果です。
さいごに
Google許すまじ!!
まぁ、頭が悪い自分が悪いんですが。実はAPIがもう一種類あって今回使ったのがhttps://apis.google.com/js/api.js
なのに対しhttps://apis.google.com/js/client.js
てやつがあるんですよね。この二つの情報が錯綜していてgapi.client.request()
を使ってリクエストを送る方法を取りました。この方法だとどんなリクエストでも送れるみたいです。client.js
にはscript.scripts.run
というやつがあってこれは今回やったGASの関数を実行する専用のようです。ということはapi.js
の中にclient.js
があるのかな?わがんね。