GoogleAppsScriptで掲示板作ってみた

Google Apps Scriptをちょっと試してみた。

以前からGoogle Drive(旧Google Docs)にはJavaScriptで書けるマクロがあって、ちょくちょく使ってたんだけど、スプレッドシートなどの中に埋め込むマクロではなく、単体のプログラムとして作成することもできるってのを最近知った。

http://f.cl.ly/items/2D1M0m2B0d3R313Y2s28/Image%202013.06.03%2018%3A43%3A20.png

Google DriveをWebで開いて、「作成」→「アプリを追加」→「Google Apps Script」を選ぶと、次回から「作成」のメニューの中に「スクリプト」っていのが選べるようになって、これで作り始める。

もちろんWeb上でブラウザから編集できて、Google Drive内に保存される。さらに実行も(スプレッドシートのマクロとして使ったときと同じく)そのままGoogleのサーバー上で実行されるので、手元にブラウザだけあればいい。これかなり画期的だと思うし、ChromeOS機なんかを視野に入れるとそういう方向になるよね、という感じ。

掲示板作ってみた

とりあえず、Webアプリケーションの基本とも言える、掲示板を作ってみた。

// data source
var book = SpreadsheetApp.openById('xxxxxxxx');
var sheet = book.getSheets()[0];
 
function doGet() {
  var app = UiApp.createApplication();
  app.add(app.createLabel('掲示板へようこそ'));
  
  // form
  var panel = app.createVerticalPanel().setStyleAttribute('border', 'solid 2px #000000');
  panel.add(app.createLabel('件名'));
  panel.add(app.createTextBox().setName('subject').setId('subject'));
  panel.add(app.createLabel('名前'));
  panel.add(app.createTextBox().setName('name').setId('name'));
  panel.add(app.createLabel('本文'));
  panel.add(app.createTextArea().setName('body').setId('body'));
  panel.add(app.createButton('投稿')
    .addClickHandler(app.createServerHandler('handle_click').addCallbackElement(panel))
  );
  app.add(panel);
  
  // posts
  var panel = app.createVerticalPanel().setId('posts');
  app.add(panel);
  gen_posts(app, panel);
  
  return app;
}
 
function gen_posts(app, target){
  target.clear();
  var values = sheet.getRange(1, 1, sheet.getMaxRows(), 4).getValues().reverse();
  for(var r = 0; r < values.length; r++){
    if(values[r][0] == '') continue;
    var panel = app.createVerticalPanel().setStyleAttribute('border', 'solid 1px #000000');
    var date = Utilities.formatDate(values[r][0], "JST", "yyyy/MM/dd HH:mm:ss");
    panel.add(app.createLabel('日時:' + date));
    panel.add(app.createLabel('件名:' + values[r][1]));
    panel.add(app.createLabel('名前:' + values[r][2]));
    panel.add(app.createLabel('本文:' + values[r][3]));
    target.add(panel);
  } 
}
 
function handle_click(e){
  var app = UiApp.getActiveApplication();
  
  // register
  sheet.appendRow([
    new Date(),
    e.parameter.name,
    e.parameter.subject,
    e.parameter.body
  ]);
  
  // reload
  app.getElementById('subject').setValue('');
  app.getElementById('name').setValue('');
  app.getElementById('body').setValue('');
  gen_posts(app, app.getElementById('posts'));
  
  app.close();
  return app;
}

gistにも置いた

動作イメージは以下のような感じ。Gifzo使ってみた

http://gifzo.net/4c4c9cff2c14e02d0bb898db9e816705fad4c142.gif

左には実際に動作してる画面、右にデータベースとして使ってるスプレッドシートの画面を開いている。初期状態では、データベースに入ってる3件分のデータが画面に表示されていて、フォームに入力してボタンを押すと、データベースに1件追加され、画面の方もそれが反映される。まさに掲示板。

スプレッドシート内のマクロではなくて、単体のGoogle Apps Scriptのファイルから、別なスプレッドシートのファイルを制御して、データの出し入れをしている。つまりスプレッドシートをデータベースとして使ってる感じ。

Excelマクロがわかる人ならすぐ理解できると思う。

ブログだろうがSNSだろうがショッピングサイトだろうが、基本はこういう感じで、データベースのデータの表示と、送られてきたデータをデータベースに記録するというだけ。理屈としてはここまで出来れば大抵のWebアプリケーションは作れるってことなので、ちょっとすごいと思った。ブラウザだけあれば作れるわけだから。

デプロイ

書いたコードは、「版を管理」の機能で、バージョンを割り当てる。そして「ウェブアプリケーションとして導入」の機能で、そのバージョンを選択して公開する。

公開したあとでコードを修正しても、公開中のプログラムには影響しない。再びバージョンを割り当てて公開すると置き換わる感じ。

開発ツールの機能

エディタ部分はシンタックスハイライトやコード補完がもちろんある。

GUIGUIで作る「ユーザーインターフェイスを構築」の機能もあるんだけど、「廃止予定」って書いてあるので使ってみてない。

あとまだ使い方がよくわからないけど、デバッガも充実していた。ブレークポイントで止めたり、変数の中身を見たりできる。

「実行トランスクリプト」を見ると、実際にどういう処理をしたかの記録があって、そこに処理時間も載ってたりする。

Logger.log('hello');

こんな感じでログも残せる。

Web API的なものを作ることはできるか

UIがあるWebアプリケーションを作れるのはわかったけど、Web API的なものは作れるか。

QUERY_STRINGを取得できて、JSONで返すことができれば、一般的なものはできるように思うので、試してみた。

QUERY_STRINGを取得

doGetで引数をもらうようにして、e.parameter.[パラメータ名] で取得できるっぽい。

function doGet(e) {
  var message = e.parameter.message;
  Logger.log(message)
}

例えばこれで、message=ほげほげ で渡された文字を取得してログに書いてる(画面には何も返してない)。

JSONを返す

レスポンスをJSONで返すやり方は、わからなかった。Content-Typeを変える方法もわからないし、レスポンスには固定的なhtmlタグが勝手に含まれてしまう。

あくまで独自フォーマットとして、何かオブジェクト(ラベルとか)を置いてその中にJSONを書くとかはできるので、それで我慢するってことかな。だからJSONPはできないってことになる。

難点

動作が遅い。

ただそこはGoogleなので、1アクセスあたりの速度はほどほどでも、それが大量に利用されてもそれ以上遅くならないようになってるのかも知れない(enchantMOONの予約フォームが殺到して落ちたという話はあるけど)。

いろいろ試した感じでは、Google Apps Scriptの動作はかなり速いんだけど、スプレッドシートを制御するところで遅いみたい。1つのセルのデータを取ってくるのに1秒くらいかかることがある。データベースとしてスプレッドシートを使うっていうところに無理があるのかな。

使いどころ

まあこれでホントに広く一般公開して使ってもらう普通のWebアプリケーションを作って実行するってのは、現時点ではちょっと難しいのかも知れない。ただ、文書をもともとGoogle Driveで管理してたりしている場合に、それとうまく連携させるのとかは超便利そう。

たとえば自分の会社では勤務時間をGoogle Driveスプレッドシートに書いてるんだけど、これを自動的に記録させたりするのはすぐできると思う。

なんか実用的なのを作ってみたい。