第3回
きっと何者にもなれない僕は、Go言語のウェブフレームワークであるRevelのドキュメントを和訳しつつ、理解を深めたいでござる。
前回 : (訳しながら)つくって覚えるRevelフレームワーク - その2 - DRYな備忘録
今回は
Introduction のチュートリアルを見ながら、簡単なアプリを一つ作る。
(´-`).。oO( 原文載せるの疲れた...
Introduction
このチュートリアルではクソシンプルなアプリをひとつ作っていきます。
- Getting started - Revelのインストールと起動までします
- Creating a new Revel app - Revelアプリのスケルトンを作ります
- The request flow - リクエストをハンドリングする段階を順に見ていきます
- Implementing the Hello World app - ちっちゃいアプリを作ってみましょう
コマンドラインインターフェースはOSXまたはLinuxを想定していますが、Windowsでも問題なく動作するはずです。
Getting started
ここでは、GoとRevelのインストール手順を紹介します。
/* 割愛しまーす!ここが参考になるかも
VPSをDebian7.1wheezyにしたのでサーバセットアップのログを取っておこうと思ったわけ 2
*/
最後に、動作を確認してみましょう
$ revel help ~ ~ revel! http://robfig.github.com/revel ~ usage: revel command [arguments] The commands are: run run a Revel application new create a skeleton Revel application clean clean a Revel application\'s temp files package package a Revel application (e.g. for deployment) Use "revel help [command]" for more information.
これで全て整いました。
Creating a new Revel app
Creating a new Revel application
Revelのコマンドラインツールを使って$GOPATH
にアプリケーションを作って起動してみます
$ cd $GOPATH $ revel new myapp ~ ~ revel! http://robfig.github.com/revel ~ Your application is ready: /Users/robfig/code/gocode/src/myapp You can run it with: revel run myapp $ revel run myapp ~ ~ revel! http://robfig.github.com/revel ~ 2012/09/27 17:01:54 run.go:41: Running myapp (myapp) in dev mode 2012/09/27 17:01:54 harness.go:112: Listening on :9000
ブラウザで http://localhost:9000/ にアクセスすると、アプリが動いているはすです 作られたアプリケーションの詳細はここで説明されています。
The Request Flow
前述のセクションではmyapp
という名前でRevelアプリを作りました。このセクションではRevelがhttp://localhost:9000
へのHTTPリクエストを受け取り、結果を表示するまでのフローを追っていきたいと思います。
Routes
まず真っ先に、Revelはconf/routes
を参照します。revel new
で自動的に生成されたroutesファイルに、以下のrouteが定義されています
GET / App.Index
この表記は
/
にGET
でリクエストが来た場合App
コントローラのIndex
メソッドを呼ぶ
ということを意味しています。
Actions
app/controllers/app.goの該当コードを見ていきましょう。
package controllers import "github.com/robfig/revel" type App struct { *revel.Controller } func (c App) Index() revel.Result { return c.Render() }
すべてのコントローラーは(直接的/間接的に)一番上に*revel.Controller
を持つ構造である必要があります。コントローラーのメソッドで、外部にpublicであり、返り値の型がrevel.Result
であるものは全てAction
として扱われます。
RevelのコントローラーにはResult
を生成する便利なメソッドが多数備わっています。上記の例の中ではRender()
メソッドを用いています。これは、自動的にテンプレートを割り当て200OKのレスポンスを返すメソッドです。
Templates
全てのテンプレートファイルはapp/views
ディレクトリ以下に配置してください。明示的にテンプレート名が与えられない場合、アクションの名前から動的にテンプレートを割り当てようとします。今回の例でも、明示的にテンプレート名が与えられていないので、App.Index
というアクション名からapp/views/App/Index.html
というファイルをGoTemplateに割り当てています。
{{set . "title" "Home"}} {{template "header.html" .}} <header class="hero-unit" style="background-color:#A9F16C"> <div class="container"> <div class="row"> <div class="hero-text"> <h1>It works!</h1> <p></p> </div> </div> </div> </header> <div class="container"> <div class="row"> <div class="span6"> {{template "flash.html" .}} </div> </div> </div> {{template "footer.html" .}}
GoTemplateが提供する関数以外にも、いくつかのRevel独自のヘルパーがあります。
上記のテンプレートは非常にシンプルな例です
- レンダリング変数に新しく
title
を追加している header.html
テンプレートを(title
をバインドして)インクルードしている- ウェルカムメッセージを表示している
flash.html
をインクルードし、メッセージがあれば表示しているfooter.html
をインクルードしている
また、header.html
では、他の表記方法も見ることができます。
<!DOCTYPE html> <html> <head> <title>{{.title}}</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <link rel="stylesheet" type="text/css" media="screen" href="/public/stylesheets/main.css"> <link rel="shortcut icon" type="image/png" href="/public/images/favicon.png"> <script src="/public/javascripts/jquery-1.5.2.min.js" type="text/javascript" charset="utf-8"></script> {{range .moreStyles}} <link rel="stylesheet" type="text/css" href="/public/{{.}}"> {{end}} {{range .moreScripts}} <script src="/public/{{.}}" type="text/javascript" charset="utf-8"></script> {{end}} </head> <body>
title
という変数がセットされていることがわかります。また、呼び元のテンプレートでmoreStyles
やmoreScripts
変数をバインドしていれば、ここでjsファイルやcssファイルが読み込まれるます。
例
{{append . "moreScripts" "src/myapp.js"}}
Hot-reload
ここでおもむろん、ウェルカムメッセージを変えてみましょう!Index.html
の、以下の箇所を編集します。
<h1>It works!</h1>
を
<h1>Hello World</h1>
このように。
ブラウザのページをリロードしてみてください。コンパイルしていないのにウェルカムメッセージが変わっていることが確認できるはずです!サーバのコンソールでは「ソースが編集されたのでリロードされた」という旨のメッセージが表示されていると思います。
Revelは以下のロケーションのファイルを監視しています。
app/
以下の全ての.goファイルapp/views/
以下の全てのtemplateファイルconf/routes
ファイル
これらのファイルが編集されると、最新のコードをコンパイルしてアプリケーションが更新されます。
今度はリアルタイムにエラーが出る様子を試してみましょう。app/controllers/app.go
を開いて以下の編集をします。
return c.Render()
を
return c.Renderx()
このように存在しないメソッドを呼んでみます。
すぐさまブラウザのページをリロードすると、良い感じのエラーメッセージが表示されているはずです。
では最後に、アクションからテンプレートにデータを渡してみましょう。
app/controllers/app.go
で、
return c.Renderx()
を
greeting := "Aloha World" return c.Render(greeting)
このように編集します。
またapp/views/App/Index.html
において
<h1>Hello World</h1>
の部分を
<h1>{{.greeting}}</h1>
このように編集します。
これにより、アクションでgreeting
という名前の変数をテンプレートにおいて.greeting
で参照できるようになったハズです。
それでは、ブラウザのページをリロードしてハワイアンな気分を味わいましょう!
The "Hello World" app
このセクションでは"Play Framework"と同じような"HelloWorld"アプリケーションをつくっていきたいと思います。先ほど作ったmyappプロジェクトのコードを使います。それでは始めましょう。
app/views/App/Index.html
を編集して、flash.html
をインクルードしているすぐ下に以下のフォームを追加します。
<form action="/App/Hello" method="GET"> <input type="text" name="myName" /><br/> <input type="submit" value="Say hello!" /> </form>
ページをリロードすると
とりあえずこのフォームを送信してみましょう。すると...
/App/Hello
に対応するアクションを書いてないので当然ですね。新しいアクション定義をapp/controllers/app.go
に追加しましょう。
func (c App) Hello(myName string) revel.Result { return c.Render(myName) }
また、テンプレート名を明示しない限りは、アクション名から動的にテンプレートを探すので、app/views/App/Hello.html
を作る必要があります。
{{set . "title" "Home"}} {{template "header.html" .}} <h1>Hello {{.myName}}</h1> <a href="/">Back to form</a> {{template "footer.html" .}}
改めてブラウザをリロードすればこのアクションとテンプレートがレンダリングされているのを確認できるはずです。
ではこれで最後です。フォーム値のバリデーションを追加し、エラーメッセージを表示してみます。
「名前」は空ではいけないし、最低でも3文字は欲しいところです。これをコントローラのバリデーションモジュールで実現してみましょう。app/controllers/app.go
を以下のように書き換えます。
func (c App) Hello(myName string) revel.Result { c.Validation.Required(myName).Message("Your name is required!") c.Validation.MinSize(myName, 3).Message("Your name is not long enough!") if c.Validation.HasErrors() { c.Validation.Keep() c.FlashParams() return c.Redirect(App.Index) } return c.Render(myName) }
これで、有効な名前文字列を入力していない場合には、このコントローラのIndex()
メソッドに戻されるようになりました。この名前とバリデーションのエラーはFlash(1リクエストの間だけ有効なcookie)に保存されます。
既存のflash.html
は、エラーやflash messageがある場合にそれを表示します。
{{if .flash.success}} <div class="alert alert-success"> {{.flash.success}} </div> {{end}} {{if or .errors .flash.error}} <div class="alert alert-error"> {{if .flash.error}} {{.flash.error}} {{end}} {{if .errors}} <ul style="margin-top:10px;"> {{range .errors}} <li>{{.}}</li> {{end}} </ul> {{end}} </div> {{end}}
ためしに1文字だけの名前を送信してみましょう。 いいですね!適切なエラーメッセージが表示され、入力値はそのままなのが分かります。
おめでとうございます。これで"HelloWorld"アプリケーションの完成です。
とりあえず
次回は、Introductionあたりで、設計や思想について学んでみたいと思ってます。
しかし、
英語の勉強にもなるし、すごくソフトウェアの勉強になるんだけど、この辺はただのチュートリアルだし、やったことあるし、他のフーレムワークとかと大差無いし、ぶっちゃけつまんなかったっす。