Gin + gormで簡単なWebアプリを作ってみた
自分でサービスを立ち上げたかったので、Go言語で簡単なWebアプリを作ってみた。
https://github.com/anraku/gin-sample
Go言語を選んだのは今一番気になっている言語だから
WebフレームワークはどれがいいのかよくわからなかったのでとりあえずGinを選択。
理由は速度が早そうだから(Martiniという同じWebフレームワークの40倍早いらしい)
あとはデータベースも使いたかったのでORMのライブラリもxormとgormを使ってみた。
最初はxormがいいような気がしたが、ドキュメントがあまり整備されていない印象。
また、実際にデータベースアクセスの処理が間違っていた時どのようなSQL文が発行されたのかが
分からずトラブルシューティングが難しいと感じた。
それにgithubの更新が少ないのも気になる。。
最終的にはgormの方を選択。ドキュメントもわかりやすく、ちょっとしたCRUDは1行程度でシンプルに書ける。
以下gormのドキュメント
全体的に黒いデザインなのもいいね!
Webアプリの概要
とりあえずGinとgormを使って簡単にCRUDができるアプリを作ってみた。
アプリはGOPATHの配下に配置する前提です。
フロントの方はドットインストールの何かの入門で作ったコードを使いました。
また、Ginを使う際は以下のコマンドを実行してGinをインストールする必要がある。
go get github.com/gin-gonic/gin
main.go
func main() { router := gin.Default() router.LoadHTMLGlob("templates/*") // 事前にテンプレートをロード // トップページ router.GET("/index", func(c *gin.Context) { // データを処理する ctrl := controllers.NewPost() result := ctrl.GetAllPost() // テンプレートを使って、値を置き換えてHTMLレスポンスを応答 c.HTML(http.StatusOK, "index.tmpl", gin.H{ "posts": result, }) }) }
最初にrouterを定義してHTMLテンプレートのロードを行う
router.GET("/index", func(c *gin.Context)
で/indexへのGETアクセスを処理するための
メソッドを作成している。
ctrl := controllers.NewPost()
はModelのメソッドにアクセスするためのstructを返し、
result := ctrl.GetAllPost()
でデータベースにアクセスし、値を取得している。
最後にindex.tmplをレスポンスとして返し、"posts"という名前のパラメータに取得したresultをセットする。
Controller
Controllerは基本データベースから値を取得し、必要であればデータの加工を行ってから 呼び出し元に返すというような実装が良いでしょう。 今回作ったのは簡単なCRUDしかないので、データベースから受け取った値をそのまま呼び出し元に返しています。
以下、Controllerの全文です。
package controllers import ( "../models" ) // Post Model type Post struct { } // Post Modelを返す func NewPost() Post { return Post{} } // idに合致する記事の情報を返す func (c Post) GetId(n int) interface{} { repo := models.NewPostRepository() post := repo.GetByPostID(n) return post } // 全記事の情報 func (c Post) GetAllPost() interface{} { repo := models.NewPostRepository() posts := repo.GetAllPost() return posts } // 全記事の件名 func (c Post) GetAllHeader() interface{} { repo := models.NewPostRepository() posts := repo.GetAllHeader() return posts } // 記事を投稿 func (c Post) CreatePost(header string, body string, author string) bool { repo := models.NewPostRepository() ok := repo.CreatePost(header, body, author) return ok } // 記事を更新 func (c Post) UpdatePost(id int, header string, body string) interface{} { repo := models.NewPostRepository() ok := repo.UpdatePost(id, header, body) return ok } // 記事を削除 func (c Post) DeletePost(n int) interface{} { repo := models.NewPostRepository() result := repo.DeletePost(n) return result }
Model
gormを使う際は以下のライブラリをgo get
して、importする必要がある
"github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql"
gormを利用するために以下のようにgormのオブジェクトとデータベースを初期化
var db *gorm.DB func init() { conn, err := gorm.Open("mysql", "root:password@/gin_sample?charset=utf8&parseTime=True&loc=Local") if err != nil { panic(err) } db = conn //DB Migrate if !db.HasTable("posts") { db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&Post{}) } }
gorm.DBのオブジェクトをグローバル変数で保持するようにして、実行時にDBへ接続するようにする。 init()はアプリの実行時に呼ばれる。
gormでは
db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&Post{})
のようにDBのマイグレーションを行える。 マイグレーションのコードも書いておけば開発時にテーブル定義をいちいち自分で作る必要がない。 Insertする処理も一緒に書いておくともっと楽ができるだろう。
マイグレーションは定義したstructをAutoMigrateの引数に渡すことで、それに対応するテーブルの作成を行う。 今回定義したstructは以下の通り
// 投稿情報の構造体 type Post struct { ID int `gorm:"AUTO_INCREMENT;primary_key"` Header string `gorm:"not null;size:255"` Body string `gorm:"not null;size:13000"` Author string `gorm:"not null;size:30"` CreatedAt time.Time `gorm:"not null"` }
上記のstructをマイグレーションすることで「posts」というテーブルが作成される。 最後にCRUDの処理をざっと記載する。
// idに合致する記事を取得 func (m PostRepository) GetByPostID(id int) *Post { var post Post db.Where(Post{ID: id}).Find(&post) return &post } // 記事を全検索 func (m PostRepository) GetAllPost() []Post { var post []Post db.Select("*").Find(&post) return post } // 記事を投稿する func (m PostRepository) CreatePost(header string, body string, author string) bool { post := Post { Header: header, Body: body, } db.Create(&post) return true } // 記事の件名と本文を更新する func (m PostRepository) UpdatePost(id int, header string, body string) interface{} { post := Post{ID: id} db.Model(&post).Updates(map[string]interface{}{ "Header":header, "Body": body, }) return true } // 記事を削除する func (m PostRepository) DeletePost(id int) interface{} { post := Post{ID: id} db.Delete(post) return nil }
まとめ
Gin + gormで割りとすぐにWebアプリが作れた(簡単なものだけど)
ORMライブラリの使い勝手としてはxormよりもgormの方が若干 CRUDの処理がシンプルに書ける印象。
ドキュメントも分かりやすく、CRUDが簡単に実装できたので 好きになりました。
また、テーブル名が構造体の名前に依存する(Post構造体にはpostsというテーブルが紐づく)ので、
テーブル名には気をつける必要がある。
Gin + gormは思ってたよりも記述量が少なく、記述もシンプルなので
個人的にはWebアプリを作る時にGoを使うという選択肢はありなように感じました。