Building Network and Services
比較的新しい話題であり、他の科目との内容の重複もあるが、当科目でもこの技術 Google Apps Script (GAS) を紹介しておく。
今日は、前回 Rails の Scaffold で作らせた memo アプリケーション に近い機能を、 クラウド上に実現する簡便(といっても以下のようにかなり煩雑ではあるが) な方法を見てみる。
今日は基本的にブラウザ内で(Googleのサーバ上で)作業する。
が、前回のメモアプリを想定して1行目にタイトル行を用意しておいていい
日付 | 題名 | 内容 |
---|---|---|
SpreadSheetの(他のアプリケーションからも行けるが今回はここから)拡張機能->Apps Script
で新しいタブが開く(これがApps Scriptエディタ; GASエディタなどとも呼ばれる)。
あらかじめ、「ファイルの追加」で HTMLファイルを1つ追加しておく。
Webアプリケーションとなる関数:以下をコード.gs
に追加。
function doGet(e) {
var tmpl=HtmlService.createTemplateFromFile('index') // さっきのファイル名
// ここにあとで行を追加する
return tmpl.evaluate() // ここはGASのお決まりの呼び方
}
用意したHTMLをただ表示するだけなら
HtmlService.createHtmlOutputFromFile('index')
でいいのだが、あとで拡張する(値をページ内に展開させる)ため
上記の関数を呼び出しておく。
JS や HTMLのインデンテーションの調整には Ctrl-[
,
Ctrl-]
といったショートカットが
使える(Atomでも同様だが)ことは知っておくといい。
「デプロイ」操作(青いボタンから入る)
HTMLに仕組みを仕込む(1): 入力のためのフォーム(ここではHTMLの手打ちが必要になる)
<form id="newData">
題名: <input type="text" name="title">
内容: <input type="text" name="content">
<input type="button" value="入力" onclick="sendIt()">
</form>
入力動作
HTML側とコード側の両方に分けてJavaScriptのコードをしくむ必要がある
コード側(受け皿)
function addData(ary) {
const sheet = SpreadsheetApp.getActiveSheet() // ①最初につくったSheetにアクセスするためのハンドル
sheet.appendRow(ary)
}
function addFromForm(form) {
addData([new Date(), form.title, form.content])()
}
この処理は1つの関数にまとめることもできるが、 あとの拡張のために2つに分けてあることを了承されたい。
sheet の取得の書き方を、上記ではちょっと手抜きで書いている(たぶんこれでも動く)。 正確に書くとこうなる(動かないときはこちらで書いてください)
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
HTML側(呼び出しのトリガー)
<script>
function sendIt() {
const form = document.getElementById("newData")
google.script.run.addFromForm(form)
}
</script>
これでテータの追加ができる筈(ためしてみて下さい)
日付の取得については手抜きをしています。ちょっと見苦しいけど。
データの一覧表示
まずHTML内に表示する場所を tableタグで用意する(この中にテンプレート領域や 繰り返しのためのJSコードが仕組まれている)
<table>
<tr><th>日付</th><th>題名</th><th>内容</th></tr>
<? for(i=1 ; i<val.length ; i++) { ?>
<tr>
<td><?= val[i][0] ?></td>
<td><?= val[i][1] ?></td>
<td><?= val[i][2] ?></td>
</tr>
<? } ?>
</table>
<? ... ?>
の表記)が見られるコードの追加
function showPage(){
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
const values = sheet.getDataRange().getValues()
// これでシートの中のデータを2次元配列として取得した
const template = HtmlService.createTemplateFromFile('index')
template.val=values
return template.evaluate()
} // この関数を用意して、doGetから呼ぶようにしよう
function doGet(e) {
return showPage()
}
体裁の調整
テーブルに枠がないと見にくいね
<style>
table, td ,th {
border:1px solid #333;
border-collapse: collapse;
}
</style>
入力した時に応答がないと使いづらいね
form.reset()
var url = ScriptApp.getService().getUrl()
window.open(url,'_top')
API化(これでスプレッドシートが簡易データベースとして外部ページから使える
ここまで見てきたコードは、doGet で簡易アプリケーションのページを表示してきた。
このとき このページのURL(デプロイされたアドレス)は、URLパラメータなし で呼ばれる。
APIとして呼ぶときにはこのURLにパラメータを何かつけて呼ぶのが一般的
なので e.parameters
(配列)が要素を持つかどうかで判断しよう。
function doGet(e) {
if( Object.keys(e.parameters).length == 0)
return showPage()
else if(e.parameter.list != undefined)
return ContentService.createTextOutput(JSONoutput())
else if(e.parameter.title && e.parameter.content)
return addFromParam(e.parameters)
else
return ContentService.createTextOutput("parameter error")
}
データを追加するAPIはこんな感じになるかな
URLの後ろにパラメータ文字列として
?title=...&content=....
が付加されるとして、
function addFromParam(param) {
addData([new Date(), String(param.title), String(param.content)])
return ContentService.createTextOutput("ok")
}
前に作った addData はそのまま活用できそう(そのために二階建にした)。
データ全体をJSON形式でそのまま返すAPIも作っておこう
function JSONoutput() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
return JSON.stringify(sheet.getDataRange().getValues())
}
上記を実施してみて下さい。
この筋書き通りでもいいし、自分なりのデータ選別をして出力させてもいい。
経過(どんなことを考えて、どんな選択を行ったか、など)と、 結果(どこまでできたか、Webアプリケーションとして成立したらそのURLも)を報告されたし。
それに加えて、(こういうサービス構築のアプローチと出会ってみての)感想も、 何かお書き下さい。