Google Apps Scriptを色々なアプリから実行する【GAS】
Google Apps Scriptにて2015年11月に新機能として実装された「Apps Script API」というものがあります(以前は、Google Apps Script Execution APIと呼ばれていました)。これは、Google Apps Scriptで用意してある関数を外部の環境(Javaや.NET、Node.jsなど)から実行できるようにするというものです。別途Google APIの認証用の手続きが必要ですが、この機能を利用するとG Suiteの利便性と利用範囲が格段に向上します。
- Googleアカウントを持つものであれば、認証をしてそのGoogle Apps Scriptの関数を直接実行する事が出来る
- ローカル環境(例えばイントラネット)に用意したHTML内でGoogle Apps Scriptの実行環境を利用してアプリケーションを作れる
- Javaや.NET、VBA(Access VBAとの連携事例を参考)やNode.jsといった言語で使用する事が出来る。
- アクセス権限を極特定の関数に絞る事が出来る
- iOSやAndroidのアプリからももちろん実行する事が可能になる。
- doGet()やdoPost()で同じような事が出来ましたが、1プロジェクト内で1個しか用意出来ない。Execution APIはダイレクトに関数を叩けるので、その制限がない。
- ただし、doGetのようにURLにつなげてパラメータを渡すわけではないので、基本POSTで送信する
- 通常、doGetのようなものを使って、REST APIを作った場合、実行後にURLがリダイレクトされて結果が出力されます。しかし、Apps Script APIは他のWeb API同様URLは固定なので、リダイレクトされると困るケースには重宝します(例えば、Amazon Echoから使うような場合)
目次
準備するもの、使用するメソッド
- 今回使用するスプレッドシート
- 今回用意したHTMLファイル
- ローカルPCに用意したWebサーバ
- Google API Client Library for JavaScript
事前準備
事前にスプレッドシートのメニューにある「セットアップ」内にある「初期化」を実行しておいて下さい。この作業により、スプレッドシートのIDがスクリプトプロパティに格納されます。この作業はデータの塊を返す関数内でopenByIdにてスプレッドシートを指定してる為で、getActiveSpreadsheetでは指定が出来ない為です。意外と嵌まりやすいポイントですので注意して下さい。
概要
Apps Script APIを利用できるようにする為には事前準備が必要です。今回のサンプルは特定のスプレッドシートのシートにあるデータの塊を取得して、HTML側にテーブルとして表示するというサンプルです。必要なものは
- Cloud ConsoleにてOAuth2.0クライアントIDを作成する
- Google Apps Script側で用意したデータの塊を返す関数
- 今回使用するスプレッドシートを実行可能APIとして導入した際に発行される現在のAPI ID
- スプレッドシートのスコープを取得する
デスクトップに置いたHTMLをそのまま実行では取得が出来ないので、別途Webサーバやアプリが必要です。自分は仮想環境内にUbuntu Linuxを入れ、手軽にWebサーバを作れるxamppを導入して環境を用意しました。WindowsでもMac OS Xでもxamppを利用できますので、通常はお使いのPCにxamppをインストールしてサーバを実行するだけでOKです。
プロジェクトを移動
Developer ConsoleにてOAuthクライアントIDを取得する
今回使用するスプレッドシートをコピーした後、まずはスクリプトエディタの画面に入ります。その後以下の手順でクライアントIDを取得します。
- メニューより「リソース」⇒「Googleの拡張サービス」を開きます。
- 出た画面の下にある「 Google Cloud Platform API ダッシュボード」をクリックします。
- 上記の▼をクリックして、選択元は自分のドメインを選び、新しいプロジェクトをクリックします。
- APIライブラリを開き、「Apps Script API」を検索して、有効にします。
- 次に認証情報を開き、「認証情報を作成」をクリックし、「必要な認証情報」を選択します。APIを呼び出す場所は「ウェブブラウザ」でOKです。
- 再度、認証情報をクリックし、認証情報を作成⇒OAuthクライアントIDを選択します。
- アプリケーションの種類は「ウェブアプリケーション」を選択し、作成します。
- 承認済みの JavaScript 生成元には、http://localhostと入力すればOKです。
- 承認済みのリダイレクト URIは、空っぽのままでOKです。
- これで作成すると、クライアントID、クライアントシークレットが発行されますので、コピーして置きます。
- 次にOAuth同意画面というタブをクリックします。この画面は新規でプロジェクトを作成した場合には、利用範囲を内部に制限することが可能です。GASから作った場合には、少し画面が異なるので注意。今回はプロジェクトをつくった場合として進めます。
- アプリケーションの種類は「内部」にし、ドメイン内のユーザに限定します。
- Google APIのスコープには今回追加で、../auth/spreadsheetsを選び追加します。
- 認証ドメインは自分のドメインのWebサーバからのみ呼び出せるようにする場合に使います。今回は空で良いです。保存をクリック。
図:Apps Script APIを有効にする
図:認証情報を追加する
図:OAuthクライアントを作成する
図:クライアントIDとシークレットが作成される
実行可能APIとして導入する
クライアントIDが取得できたら、まずは関数を用意しておきます。実行可能APIとして導入するという機能は、ウェブアプリケーションとして導入と同じく、ソースコードを変更する度に発行し直さないと行けないので注意が必要です。ソースコードを変更後に再度導入をせずに実行しても、以前のソースコードのままで返ってくるので嵌るポイントです。今回のスプレッドシートは、イチゴのデータベースを用意しそのデータの塊を取得してそのまま帰すberryget()という関数を用意しました。
実行可能APIとして導入する手順は以下の通りです。
- スクリプトエディタのメニューより、「公開」⇒「実行可能APIとして導入」を実行します
- 適当にバージョンの説明を入力して、配置ボタンを押し、続行すると現在の API IDが取得できます。アクセスできるユーザは全員で良いでしょう。
これだけです。
図:配置ボタンを押すと完了
スコープを取得する
スコープとは、アクセスするGoogleのサービスを差し、アクセスを許可するサービスを限定する事が出来ます。今回はスプレッドシートと一部のサービスのみですので、例えばGoogle Driveなどはhttps://www.googleapis.com/auth/driveとなっています。今回のスクリプトでのスコープは以下の手順で取得できます。
- どれでも良いのでとりあえず、1つ関数を実行しておき、認証を済ませておく。
- スクリプトエディタのメニューより「ファイル」⇒「プロジェクトのプロパティ」を開く
- 出てきた画面の「スコープ」を開く
- 出てきたスコープをメモしておく
HTMLファイルにID類を記述する
ここまで取得してきた各種ID等をHTMLファイルに記述します。
- CLIENT_IDにクライアントIDを記述します。シングルコーテーションで括るのを忘れずに。
- SCOPESに取得したスコープを記述します。配列の形で記述するので、複数指定が可能です。今回のケースで言えば、['https://www.googleapis.com/auth/script.storage','https://www.googleapis.com/auth/spreadsheets'];といった形で記述をします。
- scriptIdに現在の API IDで取得したIDを記述します。
GAS側の実行する関数を記述する
最後にGAS側で用意した関数を記述します。HTMLファイルの中盤にあるrequestがソレですが、関数名を記述します。今回のケースで言えば、'function': 'berryget'と記述します。しかし、関数に引数を渡したいこともあるでしょう。其の場合には、追加でparametersという項目を追加して、配列の形で引数を記述すると関数に引数として渡せます。具体的には以下のような形になります。
GAS側コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
function onOpen() { var ui = SpreadsheetApp.getUi(); ui.createMenu('▶セットアップ') .addItem('初期化', 'getMySheetId') .addToUi(); } //自分自身のIDを取得するコード function getMySheetId(){ var sheet = SpreadsheetApp.getActiveSpreadsheet(); var myid = sheet.getId(); var Properties = PropertiesService.getScriptProperties(); Properties.setProperty("mysheetid", myid); return myid; } //イチゴデータベースを取得して返す function berryget() { var Properties = PropertiesService.getScriptProperties(); var sheetid = Properties.getProperty("mysheetid"); var sheet = SpreadsheetApp.openById(sheetid); var ss = sheet.getSheetByName("berrymaster").getRange("A2:E").getValues(); return ss; } |
HTML側コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css"> <script type="text/javascript"> //Developer Consoleで設定したクライアントIDを入力 var CLIENT_ID = 'ここにクライアントIDを記述する'; //必要としてるスコープ(カンマ区切りで複数設定) var SCOPES = ['ここにスコープを記述する']; //認証を実行するルーチン function checkAuth() { gapi.auth.authorize( { 'client_id': CLIENT_ID, 'scope': SCOPES.join(' '), 'immediate': true }, handleAuthResult); } function handleAuthResult(authResult) { var authorizeDiv = document.getElementById('authorize-div'); if (authResult && !authResult.error) { authorizeDiv.style.display = 'none'; callScriptFunction(); } else { authorizeDiv.style.display = 'inline'; } } function handleAuthClick(event) { gapi.auth.authorize( {client_id: CLIENT_ID, scope: SCOPES, immediate: false}, handleAuthResult); return false; } //Execution APIを実行してスクリプト側の関数を叩くルーチン function callScriptFunction() { //現在のAPI IDを入力する var scriptId = "ここに現在のAPI IDを記述する"; // スクリプト側の関数(引数を必要とする場合は、'parameters': [sheetId]といった具合に渡せる) var request = { 'function': 'ここにGAS側関数名を記述する' }; // APIリクエストを組み立てる var op = gapi.client.request({ 'root': 'https://script.googleapis.com', 'path': 'v1/scripts/' + scriptId + ':run', 'method': 'POST', 'body': request }); //リクエストの実行と結果の受け取り op.execute(function(resp) { if (resp.error && resp.error.status) { //APIの実行に失敗した場合の処理 appenddiv('APIの呼び出し失敗:'); appenddiv(JSON.stringify(resp, null, 2)); } else if (resp.error) { //APIの実行結果、エラーが発生した場合の処理 var error = resp.error.details[0]; appenddiv('スクリプトエラーメッセージ: ' + error.errorMessage); if (error.scriptStackTraceElements) { appenddiv('スクリプトエラー:'); for (var i = 0; i < error.scriptStackTraceElements.length; i++) { var trace = error.scriptStackTraceElements[i]; appenddiv('\t' + trace.function + ':' + trace.lineNumber); } } } else { //APIの実行に成功し、帰ってきた値を処理するルーチン var data = resp.response.result; var length = data.length; var clength = data[0].length; if (length == 0) { appenddiv('データがないよ'); } else { appenddiv('<p><b>見つかったデータの詳細</b></p>'); var html = "<table border='1'>"; for(var i = 0;i<length;i++){ html += "<tr>"; for(var j = 0;j<clength;j++){ html += "<td>" + data[i][j] + "</td>"; } html += "</tr>"; } html += "</table>"; appenddiv(html); } } }); } //idがoutputのタグに結果を書き込む関数 function appenddiv(message) { var pre = document.getElementById('output'); pre.innerHTML = pre.innerHTML + message; } </script> <script src="https://apis.google.com/js/client.js?onload=checkAuth"> </script> </head> <body> <div id="authorize-div" style="display: none"> <span>Apps Script APIを実行する</span> <button id="authorize-button" onclick="handleAuthClick(event)" class="action"> 認証実行 </button> </div> <div id="output"></div> </body> </html> |
Webサーバ上に配置して実行する
作成が完了したHTMLファイルをWebサーバに配置します。Ubuntu Linuxにインストールしたxamppでは、/opt/lampp/htdocs以下が配置場所になりますので、ここにtestというフォルダを自分は作りました。testフォルダ内にstart.htmlを配置して、Webサーバを起動します。xamppの場合の起動コマンドは、