はじめに
自分のブログに書いた記事の転載です。
とある友人の紹介でGoが熱いという話を聞きましてそんなに興味なかったのですがGoをはじめてみました。
RevelってのとMartiniが良い感じらしいので両方試してようと思ったのですが、Martiniの方が推されていたのでMartiniを試してみることにしてみました。
MartiniはRubyのSinatraみたいな感じらしいですが、martini-contribでrenderやbindingといったcontribが公開されているのでこれらを必要に応じてインストールすることで便利になるようです。
とりあえずGoもWebFrameworkも初心者でよくわかりませんがシンプルなDEMOをつくってみます。
つくるもの
- とりあえずルーティングさせたい。
- テンプレートエンジンでレンダリングしたい。
材料
ディレクトリ構成
├── app.go ... ルーティングの処理をします
├── index.go ... Indexをレンダリングします
├── about.go ... Aboutをレンダリングします
└── templates
├── about.tmpl ... Aboutのテンプレートです
├── index.tmpl ... Indexのテンプレートです
└── layout.tmpl ... 全体レイアウトテンプレートです
セットアップ
go get
コマンドでmartini
とmartini-contrib/render
をインストールします。
% go get github.com/go-martini/martini
% go get github.com/martini-contrib/render
ルーティング
Martiniの根幹でもあるルーティングの処理を書いています。
- Get
/
... Index - Get
/about
... About - Get
その他
... Indexにリダイレクト
こんな感じのルーティングにします。
app.go
package main
import(
"github.com/go-martini/martini"
"github.com/martini-contrib/render"
)
func main() {
m := martini.Classic()
m.Use(render.Renderer(render.Options{
Directory: "templates",
Layout: "layout",
Extensions: []string{".tmpl"},
Charset: "utf-8",
}))
m.NotFound(func (r render.Render){
r.Redirect("/")
})
m.Get("/", IndexRender)
m.Get("/about", AboutRender)
m.Run()
}
テンプレートレイアウト
共通部分のテンプレートレイアウトを用意します。Twitter Bootstrap3
を使います。
Bootstrap超便利!
{{yield}}
にIndexとAboutテンプレートがレンダリングされたものが入ります。
templates/layout.tmpl
<!Doctype html><html lang="ja"><head><meta charset="utf-8">
<title>{{.Title}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0, maximum-scale=10">
<link href="//bootswatch.com/readable/bootstrap.min.css" rel="stylesheet">
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="//underscorejs.org/underscore.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
</head>
<body>
<nav class="navbar navbar-default" role="navigation">
<div class="container">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">Martini Demo</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li><a href="/about">About me</a></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</div>
</nav>
{{yield}}
<footer>
<div class="container">
<p class="text-center">© hogeyan</p>
</div>
</footer>
</body></html>
Indexページのレンダリング処理
レンダリング処理を書きます。github.com/martini-contrib/render
を使います。
IndexViewModel
というViewModelをつくってそれをIndexRenderに渡してレンダリングします。
index.go
package main
import(
"github.com/martini-contrib/render"
)
type IndexViewModel struct {
Title string
Description string
}
func IndexRender(r render.Render) {
viewModel := IndexViewModel{
"Martini Demo",
"Description",
}
r.HTML(200, "index", viewModel)
}
templates/index.tmpl
<div class="jumbotron">
<div class="container">
<h1>{{.Title}}</h1>
<p class="lead">{{.Description}}</p>
</div>
</div>
Aboutページのレンダリング処理
Indexページと同様に処理します。
about.go
package main
import(
"github.com/martini-contrib/render"
)
type Profile struct {
Name string
Skill []string
}
type AboutViewModel struct {
Title string
Profile Profile
}
func AboutRender(r render.Render) {
skill := []string{"TypeScript", "Sass/Compass", "Go"}
profile := Profile{
"hogeyan",
skill,
}
viewModel := AboutViewModel{
"About me",
profile,
}
r.HTML(200, "about", viewModel)
}
templates/about.tmpl
<div class="container">
<h1>{{.Title}}</h1>
<dl>
<dt>Name:</dt>
<dd>{{.Profile.Name}}</dd>
</dl>
<dl>
<dt>Skill:</dt>
{{range .Profile.Skill}}
<dd>{{.}}</dd>
{{end}}
</dl>
</div>
動かしてみる
gin
を使って起動させることで、毎回go run *.go
ってやる必要もなくなるのと自動更新してくれるのでめちゃくちゃ楽になります。早速使ってみましょう。
gin
をインストールする。
% go get github.com/codegangsta/gin
つかってみる
gin
コマンドを実行するだけです。簡単です!
% gin
GitHubにもソースを置いておきました。