このエントリーをはてなブックマークに追加

golangのWebフレームワーク、revelの機能紹介

golangでのweb application frameworkはいろいろなものがあります。その中でどれがいいのかというと、どれも鋭意開発途中だし、新しいのも出てくるしでなんとも言えません。

その中で、revelというフレームワークが結構昔からあります。これは、Railsに例えられるようになんでも揃ってるいわゆる重量級なフレームワークです。

薄いフレームワークであれば、標準のnet/httpでもいいような気もちょっとするので、現在このrevelを使って実際に作ってみています。

なお、以下のページを参考にさせていただきました。

特徴

いろいろな特徴がありますが、上記サイトでは挙げられていないrevelのいいところをここでは紹介してみます。

  • コマンド一発でデプロイ用zipファイルが出来上がる
  • i18n対応
  • いろいろなところにhookを仕込める
  • dev/prodなど実行環境を指定できる。しかもconfigも簡単に書ける

ほかにもredisも対応しているsession管理やjob実行やvalidation、WebSocket対応などいろいろあるのですが、そこはマニュアルを見て頂くとより分かりやすいかと思います。

コマンド一発でデプロイ用zipファイルが出来上がる

revel packageコマンドを実行すると、 tar.gzファイルが出来上がります。これをサーバーに送って展開すると、

.
|-- run.bat
|-- run.sh
|-- sample-app
|-- sample-app.log
|-- sample-app.tar.gz
`-- src
    `-- github.com
        |-- revel
        `-- tsukinowasha
             `-- sample-app

という感じでファイルが展開されます。あとはrun.shを実行すれば、すぐに実行できます。

ちなみにsrc以下はrevelとアプリだけです。それ以外は含まれていません。revel以下にはconfファイルやtemplateファイルなどがあり、バイナリやgoファイルなどは含んでいません。アプリ以下はgoファイルも含めて全部入っています。revelは実行時にbuildするのでこれは仕方ないかな、と思います。

bindataで一つのバイナリにパッケージするという方式の方が良いかもしれませんが、この方式でも問題ないかなぁと思っているところです。ただ、revel package方式はソースコードも含まれているので、それはまずいということであればbindataを使うほうがいいと思います。

i18n対応

message/labes.jamessage/labes.jaというファイルを用意しておくと、ブラウザの言語設定に従ってそのメッセージを返してくれます。

messages.jaは以下の様なファイルです。(別に.で区切らなくても一意であれば構いません)

mode.dev.label=検証系
login.title=ログイン

こうしておいて、テンプレートで

<h3>{{msg . "login.title" }}</h3>

などと書けば、言語によってmessages.jaやmessages.enの内容を参照してくれます。

hook

revelはInterceptorという、リクエスト中のいろんなタイミングに仕込めるHookがあります。

例えば、以下のようにしておくと、リクエストの処理をする前にcheckUser関数が走ります。

func checkUser(c *revel.Controller) revel.Result {
    if user := connected(c); user == nil {
       c.Flash.Error("Please log in first")
       return c.Redirect(App.Index)
    }
  return nil
}

func init() {
   revel.InterceptFunc(checkUser, revel.BEFORE, &Users{})
}

revel.BEFOREがタイミングの指定です。他にはAFTERやpanic時に呼び出されるPANICなどがあります。

これを利用すると記述が共通化出来て便利です。

実行環境制御

revel runコマンドで実行するとdevモードで立ち上がり、ログ表示が詳細になったりhot reloadingが有効になったり、デバッグ表示が出たりします。

この辺りはconf/app.confに書かれてあります。

[dev]
mode.dev=true
results.pretty=true
watch=true

db.host = localhost

[prod]
mode.dev=false
results.pretty=false
watch=false

db.host = prod-db.example.com

このように、セクションで区切ることで、実行環境を選択できます。[staging]などを追加することも出来ます。これによって動作を変えることが出来ます。

db.hostという部分は自分で足したものです。codeの中からは

dbhost := revel.Config.StringDefault("db.host", "localhost")

というように取得できますので、これを使えば環境ごとに違うホストにつなぎにいく、ということができます。(上記例はdefaultをlocalhostに設定しています)

ちなみに、上記revel packageコマンドでパッケージを作成すると、prod環境で立ち上がるようにスクリプトが作成されています。ちょっとした気遣いが便利。

テンプレートでのCustom Functions

こんな感じでrevel.TemplateFuncsに関数を定義しておけば、templateで使えます。

func init() {
             revel.TemplateFuncs["eq"] = func(a, b interface{})
             bool { return a == b }
}

ハマったところ

最後にrevelを使う時にハマったところを紹介します。といっても今のところ一つぐらいしかないですが。そのうち更新します。

initタイミング

package内の変数を起動時に書き換えようとしたら、ちゃんと変更してくれませんでした。OnAppStartで指定することでちゃんと変更されるようになりました。

var DB = "localhost"

func init() {
   // これは期待通りに動かない
   // DB := revel.Config.StringDefault("db.host", "localhost")
   revel.OnAppStart(changeDBHostFunc)  // 関数を登録
}

まとめ

今回の記事ではrevelのいろいろな機能を紹介しました。結構便利ではないでしょうか。

revelは重量級と言われるだけあり、機能が豊富です。revelはぼくにとっては学習コストはさほど高いものではなく、かなりすんなり使いはじめることが出来ました。そうなると、機能を自分で実装したり後から足すことはない分、楽に開発ができています。

なお、同じ位置づけのものとしてはbeegoがありますが、こちらはまだ試していません。