go + gin + gormでtodo Webアプリを最速で作ってみた
go歴3ヶ月でtodo webアプリを作ってみました。
環境:Macbook + Goland
#機能概要
- todoリスト
- todo作成
- todo更新
- todo削除
ginのインストール
go get -u github.com/gin-gonic/gin
その他ライブラリのインストール
GORM:O/Rマッパー
- gormのインストール
go get -u gorm.io/gorm
- gorm sqliteドライバのインストール
go get -u gorm.io/driver/sqlite
configライブラリのインストール
go get gopkg.in/ini.v1
todoアプリの開発
ディレクトリ構成
・config
コンフィグ設定ファイル
・models
モデルファイル
・templates
テンプレートディレクトリ
configファイルを作成する
config.iniを編集する
[web]
logfile = webapp.log
[db]
driver = sqlite3
name = webapp.sql
コンフィグファイルをロードする
config.iniを変数にロードする
config/config.go
package config
import (
"database/sql"
"gopkg.in/ini.v1"
"log"
)
type ConfigList struct {
SQLDriver string
DbName string
LogFile string
}
var Db *sql.DB
var err error
var Config ConfigList
func init() {
LoadConfig()
}
func LoadConfig() {
cfg, err := ini.Load("config.ini")
if err != nil {
log.Fatalln(err)
}
Config = ConfigList{
SQLDriver: cfg.Section("db").Key("driver").String(),
DbName: cfg.Section("db").Key("name").String(),
LogFile: cfg.Section("web").Key("logfile").String(),
}
}
モデルを作成する
ファイル:base.go
初期テーブルの作成やDBインスタンスの作成
package models
import (
"fmt"
_ "github.com/mattn/go-sqlite3"
"go_gin_todo/config"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
var Db *gorm.DB
var err error
const (
tableNameTodo = "todos"
)
func init() {
Db, err = gorm.Open(sqlite.Open(config.Config.DbName))
if err != nil {
fmt.Errorf("error:%v", err)
}
Db.AutoMigrate(&Todo{})
}
ファイル:todo.go
todoテーブルのO/RマッピングモデルとCRUD関数の定義を行う
package models
import (
"gorm.io/gorm"
)
type Todo struct {
gorm.Model
Content string
}
func CreateTodo(content string) (err error) {
todo := Todo{
Content: content,
}
Db.Create(&todo)
return err
}
func DeleteTodo(id int) (err error) {
Db.Delete(&Todo{}, id)
return err
}
func GetTodo(id int) (todo Todo, err error) {
Db.Find(&todo, id)
return todo, err
}
func UpdateTodo(t Todo) (err error) {
Db.Save(&t)
return err
}
テンプレートファイルを作成する
ファイル:templates/todo/list.html
todoリストと作成フォームのhtml
<html>
<h1>
{{ .title }}
</h1>
<form role="form" action="/todos/save" method="POST">
<div class="lead">Todos作成</div>
<div class="form-group">
<textarea class="form-control" name="content" id="content" placeholder="Todoを追加" rows="4"></textarea>
<br/>
<br/>
<button class="btn btn-lg btn-primary pull-right" type="submit">作成</button>
</div>
</form>
<hr />
{{ range .todos }}
<p><a href="/todos/edit?id={{.ID}}">{{ .ID }}:{{ .Content }}</a></p> <a href="/todos/destroy?id={{ .ID }}">[削除]</a>
{{end}}
</html>
ファイル:templates/edit.html
todo変更フォーム
<html>
<h1>
{{ .title }}
</h1>
<form role="form" action="/todos/update" method="POST">
<input type="hidden" name="id" value="{{.todo.ID}}" />
<div class="lead">Todos更新</div>
<div class="form-group">
<textarea class="form-control" name="content" id="content" placeholder="Todoを追加" rows="4">{{.todo.Content}}</textarea>
<br/>
<br/>
<button class="btn btn-lg btn-primary pull-right" type="submit">更新</button>
</div>
</form>
<hr />
</html>
処理関数を作成する
ファイル:main.go
todoのCRUD処理を行うメインファイル
package main
import (
"github.com/gin-gonic/gin"
"go_gin_todo/config"
"go_gin_todo/models"
"io"
"log"
"net/http"
"os"
"strconv"
)
func setupRouter() *gin.Engine {
//ログ設定
f, _ := os.Create(config.Config.LogFile)
gin.DefaultWriter = io.MultiWriter(os.Stdout, f)
//templateディレクトリ設定
r := gin.Default()
r.LoadHTMLGlob("templates/**/*")
// todo create
r.POST("/todos/save", func(c *gin.Context) {
models.CreateTodo(c.PostForm("content"))
c.Redirect(http.StatusMovedPermanently, "/todos/list")
})
// todo create
r.POST("/todos/update", func(c *gin.Context) {
id, _ := strconv.Atoi(c.PostForm("id"))
content := c.PostForm("content")
todo, _ := models.GetTodo(id)
todo.Content = content
models.UpdateTodo(todo)
c.Redirect(http.StatusMovedPermanently, "/todos/list")
})
//todo edit
r.GET("/todos/edit", func(c *gin.Context) {
id, err := strconv.Atoi(c.Query("id"))
if err != nil {
log.Fatalln(err)
}
todo, _ := models.GetTodo(id)
c.HTML(http.StatusOK, "edit.tmpl", gin.H{
"title": "Todo",
"todo": todo,
})
})
//todo delete
r.GET("/todos/destroy", func(c *gin.Context) {
id, err := strconv.Atoi(c.Query("id"))
if err != nil {
log.Fatalln(err)
}
models.DeleteTodo(id)
c.Redirect(http.StatusMovedPermanently, "/todos/list")
})
//todo list
r.GET("/todos/list", func(c *gin.Context) {
var todos []models.Todo
models.Db.Find(&todos)
c.HTML(http.StatusOK, "list.tmpl", gin.H{
"title": "Todo",
"todos": todos,
})
})
return r
}
func main() {
r := setupRouter()
r.Run(":8080")
}
実行イメージ
go run main.go
ブラウザで以下を開く
http://localhost:8080/todos/list
以上になります。
webアプリを作成するにはかなりお手軽なフレームワークかと思います。