JGate (AppJet) の使い方
今さら感あふれてるっぽいけど JavaScript でサーバサイドもプログラミングできる JGate というサービスを使ってみたらすごく面白かったので、使い方を簡単に解説してみる。
JGate っていうか、もともとは AppJet というアプリケーションホスティングサービスがあったんだけど、Google に買収されてホスティングを止めてしまったため、その代替として AppJet と同じホスティングサービスを提供しているのが JGate という感じらしいです。
JavaScript でサーバーサイドを書けるのだけで十分楽しいんだけど、さらに面白いと思ったのはサーバサイドのソースコードも全部誰からでも見えてしまうこと。強制オープンソースというクライアント JavaScript の特性がサーバサイドにまで適用されている。
IDE とアプリケーションファイルの構成
アカウントを作って "Create Apps" をクリックすると表示されるのが以下の画面で、基本的にはこの Web 上の IDE で 1 ファイルを編集していくことによってアプリケーションを作って行く。GAE とか Heroku よりだいぶ手軽な感じがする。
ファイルは特殊なコメントで区切られていて、複数のコンテンツを記述することができる。
/* appjet:version 0.1 */ // バージョン宣言 (必須) /* appjet:server */ // サーバサイド側の JavaScript を書く /* appjet:library */ // ライブラリとしてサーバサイド側の JavaScript を書く // 他のアプリケーションのサーバサイド JavaScript からも import 文で読み込めるようになる /* appjet:client */ // クライアント側の JavaScript を書く // 出力される HTML の body->script タグの中に出力される /* appjet:css */ // スタイルシートを書く // 出力される HTML の body->style タグの中に出力される
URL のマッピング
Handling URLs に詳しく書かれているけど、if-else で切り分けていく方法や Sinatra 風の DSL っぽいディスパッチャを使う方法がある。あと lib-text-converter のソースを見ると、patternDispatch() という関数で正規表現を使ってマッピングする方法もあることが分かる。
以下は Sinatra っぽいディスパッチャを使った例。
/* appjet:version 0.1 */ function get_main() { printp('hello from GET /') } function post_main() { printp('hello from POST /') } function get_foobar() { printp('hello from GET /foobar') } function post_foobar() { printp('hello from POST /foobar') } dispatch()
'GET /' と 'POST /' に対応する処理はそれぞれ予約された get_main() / post_main() 関数の中に書く。それ以外のリクエストについては、例えば 'GET /foobar' と 'POST /foobar' がそれぞれ get_foobar() / post_foobar() 関数に対応する。
HTML の出力
HTML の出力については HTML Document や Printing Text and HTML あたりに詳しい。
テンプレートエンジンは無くて*1、昔の Perl の CGI スクリプトみたいに print() でゴリゴリ出力していく感じだけど、HTML のタグ名に対応した大文字の関数が定義されているので、わりと読みやすい感じに書ける。
/* appjet:version 0.1 */ print( H1('ぼくのホームページにようこそ'), DIV( {'class':'content'}, P('ようこそぼくのホームページへ'), P('スタミナカレー:'), IMG({'src':'http://gyazo.com/311bf1c226035174353b251bb21ea9c2.png'}), BR(), link('http://yahoo.co.jp', '出口') ) )
print() がいい感じにスマートで、デフォルトでは全て画面出力をエスケープし、html() 関数を使うことで生の HTML を出力するようになっている。オブジェクトは table/tr/td タグ、配列は ul/li タグという風に自動的に整形して出力してくれたりするのも便利です。
他にも a タグを出力する link() 関数やパラグラフを出力する printp() 関数あったり、フォームに関しては PHP の HTML_QuickForm 風のライブラリが用意されていたりする (Forms 参照)。
DB アクセス
storage という特別なグローバルオブジェクトを使って恒久的なデータを格納する。
storage には StorableObject と StorableCollection という 2 つのクラスのオブジェクトを格納することができて、それぞれ関係データベースで言うところのレコードとテーブルに該当する感じ。
/* appjet:version 0.1 */ import('storage') storage.books = new StorableCollection() // 挿入 storage.books.add({author: 'Kurt Vonnegut', title: 'The Sirens of Titan'}) storage.books.add({author: 'Kurt Vonnegut', title: 'The World According to Garp'}) // 読み込み var a_book = storage.books.filter({title: 'The World According to Garp'}).first() // 更新 a_book.author = 'John Irving' // 削除 storage.books.remove({author: 'John Irving'}) // StorableObject 単体でも DB に保存することができる storage.config = new StorableObject() storage.config.password = 'kogaidan' print(storage.books) print(storage.config.password)
詳しくは StorableCollections と Persistent Storage を参照。
その他の機能/ライブラリ
Cron による定期処理*2とか wget とかやりたいことは一通りできるっぽいし、他のユーザが作ったライブラリを自分のアプリの中で使うこともできる。
以下は便利そうだと思ったライブラリの一覧。他にもいろいろあるのでここらへんを見てみるといいです。
- http://lib-jlp.jgate.de/
http://lib-xpath.jgate.de/http://lib-html-xpath.jgate.de/- 指定した URL から XPath を指定して要素を取得する xget() 関数
- http://lib-dispatch-plus.jgate.de/
- より複雑なディスパッチを扱う
- http://lib-cache.jgate.de/
- mememcached みたいなインタフェースでデータをキャッシュする
上記のようなライブラリを自分で作ることもできて、http://lib-ライブラリ名.jgate.de/ という名前でアプリを作り、/* appjet:library */ というコメントの下に関数とかクラスを書き、他のアプリから import() で呼べばそのまま使えるようになる (Libraries 参照)。
まとめ
ここまで知ってればだいたいのものは作れると思う。僕も youpy さんの lib-text-converter を使って喫茶店の名前変換を jgate に移植したり、シンプルな Wiki みたいなやつを作ってみたりしました。
結構落ちてることが多かったり、IDE で日本語が入力できなかったり*3と微妙なところも多々あるんだけど、軽いアプリだったらほんとに手軽に作れるので、JGate 使ってみるといいと思います。
*1:テンプレートエンジンみたいなやつありました http://studyroom.g.hatena.ne.jp/tily/20100620/1277010087
*2:現状停止しているらしい http://forum.jgate.de/viewtopic.php?id=51 でも中の人に頼むと個別対応してもらえるようです http://twitter.com/js4all/status/17601577092
*3:http://apps.jgate.de/platform/editsettings で "Preferred Editor" を "AppJet" に設定したら入力できた via http://twitter.com/m_satyr/status/15099070717