Google Apps Scriptには、ウェブアプリケーションを公開したりするために「doGet」「doPost」という特別な関数があります。パラメータを加えて渡して上げることで、スプレッドシートのデータなどをJSONで受け取ったり、ウェブページを生成して、ウェブアプリケーションを表示したりなど、非常に重要な機能の1つです。この仕組を使うことで、自作のREST APIを作ることも可能です。
今回は、この「doPost」「doGet」を利用して、実行をするとスプレッドシートに書き込まれるといったものを作ってみたいと思います。
難易度:
目次
今回使用するスプレッドシートや資料
- doPost関数
- doGet関数
- 今回使用するスプレッドシート
- ContentServiceクラスの各種メソッド
概要
doGetは、URLに繋げてパラメータを与えて送ります。HTTP通信のGETなわけですが、こちらのほうが利用する範囲が広いんじゃないかなぁと。思いつくだけで言えば、
- パラメータ付きで送ってスプレッドシートの値をJSONで取得する(しかも、フィルタした後の値とか)
- 予め組んで置いたURLをメールに記載して、クリックすると発動する何か(例えば、承認されるとか、ファイルが作られるとか)
- 与えるパラメータに応じて表示するHTMLを切り替える
- パラメータを可変でユーザが選んだり、与えたパラメータによってデータを書き換える。
- Google Apps Scriptではウェブアプリケーション公開用のメソッドでもある。
doPostは、URLに繋げるのではなくHTTP通信にパラメータを渡すPOST通信です。GETと違いパラメータはURLには出てこないので、認証などを要するようなケースで利用されます。また、バイナリデータを送ったり(アップロード)などでもPOSTを使いますね。
両者の違い、用途としてデータを取得する場合にはGET、送る場合にはPOSTといった感じで使い分けをすると良いでしょう。
※doGetおよびdoPostは、同居は可能ですが1プロジェクトで1個しか用意できないので、複数用意したい場合には仕組みで分けるか?複数プロジェクトを作って運用する必要があります。
doGet
仕組み
仕組みは至って簡単なものです。以下のような感じです。
- doGetはパラメータを受け取れるようにdoGet(e)という形で記述を行う。
- 送る側は、公開されてるウェブアプリケーションのURLにパラメータをくっつけて、叩くだけ。
- 付け加えるパラメータは、?param1=kinoko¶m2=takenoko みたいな感じ。この場合2つのパラメータを取得できる
- パラメータを受け取る側は、e.parameter.param1でkinokoという値が取得できるという塩梅です。
- 受け取ったパラメータを後は煮るなり焼くなり好きにする。
- 最後にreturnで、例えばHTML表示をしたり、JSONデータを返して上げれば、プログラムがそのままURLからデータを取得出来るようにもなる。(WebAPI的なものが作れるわけです)。
実行結果
コードを作ってGETパラメータ文字列を組み立ててURLを叩きます。例えば今回使用するスプレッドシートに於いて、【情報通信業】の【2009】の年のデータを引き出したい時には以下のようなURLを組み立てます。
すると、{“value”:194} といったようなJSONで返ってきます。param1が業態の指定・param2が年度の指定になります。業態の指定がおかしかったり、指定した年度の情報がない場合には、valueの値はerrorとして返すようにしています。上記のURLをクリックすると実際に値が返って来ます。
※ただし出力時に、URLはリダイレクトしますので、何かプログラムでデータを取得する場合にはそれを考慮する必要があります。
ソースコード
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 |
//書き込みスプレッドシートID var gasheet = "書き込み先のスプレッドシートのIDをここに記入"; function doGet(e) { //受け取るパラメータを用意する var filterparam = e.parameter.param1; var nendoparam = e.parameter.param2; var rowData = {}; //JSONオブジェクト格納用の入れ物 if (e.parameter == undefined) { //パラメータ不良の場合はundefinedで返す var getvalue = "undefined" rowData.value = getvalue; var result = JSON.stringify(rowData); return ContentService.createTextOutput(result); } else { var id = gasheet; //スプレッドシートのID var sheet = SpreadsheetApp.openById(id).getSheetByName("シート1"); var range = sheet.getRange("A1:Q").getValues(); var record = range.length; var colman = range[0].length; //年度の特定 var nencnt = 0;; for(var i = 1;i<record;i++){ if(nendoparam == range[i][0]){ nencnt = i; break; } } //年度で見つからなかった場合の処理 if(nencnt == 0){ var getvalue = "error" rowData.value = getvalue; var result = JSON.stringify(rowData); return ContentService.createTextOutput(result); } //業態の特定 var gyocnt = 0; for(var j = 1;j<colman;j++){ if(filterparam == range[0][j]){ gyocnt = j; break; } } //業態が見つからなかった if(gyocnt == 0){ var getvalue = "error" rowData.value = getvalue; var result = JSON.stringify(rowData); return ContentService.createTextOutput(result); } //みつかった値をJSONで返す var getvalue = range[nencnt][gyocnt]; rowData.value = getvalue; var result = JSON.stringify(rowData); //ログ出力と値の出力 Logger.log(result); return ContentService.createTextOutput(result); } } |
ポイント
- 今回の事例は非常に単純な指定したパラメータで値を返すだけですが、複数データを返すような場合には、JSONオブジェクト作成の部分で階層的なコードを書く必要性があるでしょう。
- 複雑なデータの出力については、SheetAsJsonのコードを再利用するとやりやすいかもしれません。
- param1やparam2といった部分はソースコード内で決めることができるので、自由にネーミングを付けて下さい。
- 最終的にContentService.createTextOutputにてJSON文字列を返してあげます。これをやらないと、他のプログラムからJSON出力を取得できません。
doPost
実行結果
※入力して送信するとスプレッドシートに書き込まれます。
ソースコード
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 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 |
//書き込み先スプレッドシートID var gasheet = "ここに参照先スプレッドシートのIDを入れる"; //POSTで受け取ってスプレッドシートへ書き込み function doPost(e) { var test = e.parameter.name; var ss = SpreadsheetApp.openById(gasheet); var sheet = ss.getSheetByName("POST"); var array = [e.parameter.name,e.parameter.sex,e.parameter.food,e.parameter.mycar]; sheet.appendRow(array); //結果をリターン return makeContent(makeResponse(e,"POST")); } //スプレッドシートのIDチェック用 function checkId(id) { var ss = SpreadsheetApp.openById(gasheet); var sheet = ss.getSheetByName('POST'); var range = sheet.getRange(1, 1, sheet.getLastRow(), 1); var values = range.getValues(); var result = false; values.forEach(function (row) { row.forEach(function (val) { if (result) { return; } if (val === id) { result = true; return; } }); }); return result; } //投稿内容をJSONで組み立てて返す function makeResponse (e, type) { var valid = checkId(e.parameter.presentCode); e.parameter.valid = valid; var s = JSON.stringify({type: type, params: e}); if (!e.parameter.callback) { return {mime:ContentService.MimeType.JSON, content: s}; } else { return {mime: ContentService.MimeType.JAVASCRIPT, content: e.parameter.callback + "(" + s + ");" }; } } //投稿コンテンツ内容をJSONで返す function makeContent(content) { return ContentService.createTextOutput(content.content).setMimeType(content.mime); } |
意外とシンプルです。getActiveSpreadsheetが使用できないので、openByIdで開くようにしています。また、formから送られてくるデータはformの各コントロールに付与してるname属性を利用しています。なので、e.parameterの後にname属性を付けると、その値が取得できるので、これを順番に配列に格納し、appendRowで最終行に登録しています。
HTML側コード(POST送信用)
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 |
<html> <head> <title>Google Spreadsheet書き込みテスト</title> <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css"> <script type="text/javascript"> function disp(){ // 「OK」時の処理開始 + 確認ダイアログの表示 if(window.confirm('本当にいいんですね?')){ //FORMデータを送信する document.getElementById("formman").submit(); document.getElementById("kinoko").innerHTML = "<b>ありがとう</b>"; }else{ window.alert('キャンセルされました'); // 警告ダイアログを表示 } } </script> </head> <body> <div id="kinoko"> <form id="formman" action="ここにPOST側ウェブアプリケーションURLを入れる" method="post" target="_blank"> ニックネーム:<input type="text" name="name" id="input1"/><p> 性別: <input type="radio" name="sex" id="input2" value="男" />男 <input type="radio" name="sex" id="input3" value="女" />女<p> 好きな食べ物: <select name="food" id="input4"> <option value="すき焼き">すき焼き</option> <option value="寿司">寿司</option> <option value="天ぷら">天ぷら</option> <option value="あげパン">あげパン</option> <option value="カレーライス">カレーライス</option> </select><p> 愛車: <select name="mycar" id="input5"> <option value="GT-R">スカイラインGT-R</option> <option value="トレノ">スプリンタートレノ</option> <option value="シビック">シビックEK9</option> <option value="インプレッサ">インプレッサ</option> <option value="ランエボ">ランサーエボリューション</option> </select><p> <center> <p><input type="button" value="確認ダイアログ" onClick="disp()" class="action"></p> </center> </form> </div> </body> </html> |
Formの各要素のname属性がdoPost側に渡るe.parameterの値を取り出すときの要素になるので、重複しないようにname属性は付けなければなりません。また、送信ボタンで実行する関数の中で、document.getElementById(“formman”).submit();とあるけれど、これがフォームデータを送るコマンド。その送信先が、formタグのactionに記入されてるURL。これはスプレッドシートの公開URLです。
※全て用意が完了したらウェブページとして一度公開し、URLを取得。一度公開を無効化して、URLをHTML側のFORMの送信先に入れて、再度公開すると使えるようになります。
ポイント
- 今回書き込むシートのシート名はPOSTである。
- ウェブアプリケーションとして公開した時の公開URLは別途必要になる。
- ウェブアプリケーションとして公開する場合、実行権限は今回は自分自身のみにして、他の人が実行しても自分が実行した事になるようにしている。
- 完全フリーで公開する場合には、実行権限は自分自身であっても、投稿許可は匿名も可にしておく必要性がある。
スマフォのショートカットアプリで使う
GASで作成したdoGetやdoPostのURLに対してパラメータを投げることで、ボタン一発で色々発動させる事が可能です。例えば、ボタン一発で現在まで届いてる申請のサマリーを自分宛てにPDFで送りつけるスクリプトを作っておけば、PC立ち上げてなんてやらずとも、スマフォだけで完了します。緊急一斉通知用に作って置くと、何かの役に立つかもしれません。
また、パラメータを変更して、いつでもボタンぽち1発でメンバー招集する投稿をSlackに投げて飲みに行ったりなど、よく使うものを作り込んでおくと、恐ろしく簡単に自動化が可能です。IFTTTでタスクランナーを噛ましておけば、様々なウェブサービスを手元で発動も可能。
iOSで使ってみる
iOS12よりショートカットアプリという新機能が搭載されました。いわゆるPCのショートカットリンクと同じもので、特定のリンクをポチるだけで、起動させることが出来るもので、これにGoogle Apps Scriptの今回の機能を利用する事で、ボタンひとつで遠隔でGoogle Apps Scriptを実行させてしまおうというものです。使い方は以下の通り
- ショートカットアプリをインストールしておき、起動する
- 右上の+をクリックし、出てきた検索窓に「URL」と入力
- 「URL」という項目を選び、続けて「URLの内容を取得」も選びます
- URLにdoGetで作ったexecの付くURLを入力します。
- URLの内容を取得ボックスの方法は今回は「GET」を選択。
- 完了ボタンの下にある変なマークのアイコン⇒設定⇒名前で名前をつけておきましょう。アイコンは独自画像も使えます。
- 同じく設定にて、「Siriに追加」をタップ⇒赤丸をタップ⇒付けた名前で呼ぶ⇒設定完了。
- ホーム画面に追加をするとブラウザが立ち上がる。支持にしたがって、ホーム画面に追加をすると完了。
- POSTなども選べます。また送信時用のヘッダも付けられるので、ちょっと複雑なものもつくれそうです。
- 完了ボタン押して終了です。
※コンテンツとプライバシーの制限の許可されたAppにてSiriと音声入力がONになっていないとSiriから呼び出しは出来ません。
図:ショートカットアプリの設定画面
図:ショートカットの細かな設定はやっておきましょう。
図:Siriで実行してみた
Androidで使ってみる
Androidの場合、HTTP Requestを行うアプリは結構あります。HTTP Request Shortcutsというアプリでは、非常に詳細で細かくパラメータ、ヘッダー、オプション、Authenticationなどを設定可能で、iOSのそれよりも高機能です。
- アプリをインストールしておく
- プラスボタンを押して、新しいショートカットを作る
- From scratchを選択する
- 名前、説明、show as app shortcut on launcherにチェックを入れる
- MethodはGETやPOSTを選ぶ。今回はGETで。
- URLにGASで作成したexecのついたURLを入力しておく
- Authenticationは認証が必要な場合。Basic認証やDigest認証が使えます。OAuth2認証(Bearer認証)使えないので、doGet/doPostは公開されてるURLである必要がある。そのためここは、今回はNo Authenticationを選ぶ
- Add Headerでヘッダを加えられる。今回はヘッダは無し。
- Response Settingsではレスポンスを受け取ったらどういう動作を行わせるかを決定できる。simple toastで通知のみにした。
- Actionでは成功時や失敗時などのアクションを指定できる。成功したら別のショートカットを起動といったリレーも可能。
- Advanced Settingsでは、実行時に確認求めたり、タイムアウトの設定など細かい設定が可能
- 隣にある{}マークのアイコンは、細かなパラメータバリューを送る時に利用します。
- チェックマークを押す
- その後作ったショートカットをロングタップすると、Place on home screenというのがあるので、選択すると画面に一発実行用ショートカットが配置されます。これは、Chromeのホーム画面に追加と同じようなものになります。
図:マニアックでサイバーなアプリですね
関連リンク
- Insert new rows into Google Spreadsheet via cURL/PHP – HOW?
- Google Apps Script ウェブアプリケーション Google Sites ガジェット URLリクエストパラメータ
- 【GAS】複数のdoGet関数の結果を1つのプロジェクトに収納するシンプルな方法
- How to get a URL string parameter passed to Google Apps Script doGet(e)
- How to Make a RESTful API or Service with Google Apps Script
- Google Apps Script で spreadsheet のデータを JSON として読み込む
- pamelafox / exportjson.js
- SheetAsJson
- Google Apps Scriptを使って簡易APIをサクッと作る
- スプレッドシートとgoogle apps scriptで簡易APIを作ってalamofireからget/postする
- 拡張なしでオブジェクトのJSON文字列化、JSON文字列のパースを行う方法
- iOS12の「ショートカット」アプリで、なんちゃってプログラミングしてみた
[…] 、Google Sitesにガジェットで貼り付ける時に、1つのプロジェクトで複数のガジェットを実現可能になる利点もあります。この仕組自体はGoogle Apps ScriptでGET・POSTにて一度紹介しています。 […]
[…] VBAとの大きな違いは、ローカルで動いているわけではないので、トリガー機能を使うことで真夜中に自動でプログラムを動かしたり、Web API化しておいて、他のプログラムから受け待ちをしておく事も可能である点。Excelでも数分起きに実行は出来なくもないのですが、PCを動かしたままにしておく必要があります。 […]
[…] VBAとの大きな違いは、ローカルで動いているわけではないので、トリガー機能を使うことで真夜中に自動でプログラムを動かしたり、Web API化しておいて、他のプログラムから受け待ちをしておく事も可能である点。Excelでも数分起きに実行は出来なくもないのですが、PCを動かしたままにしておく必要があります。 […]
[…] SuiteではGoogle Apps Script上でdoGet/doPostを用いたり、Google Apps Script […]