go + Echo + gormでtodo Webアプリを最速で作ってみた
go + ginを使いまわしてEchoでTodoアプリを作ってみました。
環境:Macbook + Goland
#機能概要
- todoリスト
- todo作成
- todo更新
- todo削除
Echoのインストール
go get github.com/labstack/echo/v4
その他ライブラリのインストール
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>
<head>
</head>
<body>
<form role="form" action="/create" 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="/edit?id={{.ID}}">{{ .ID }}:{{ .Content }}</a></p> <a href="/destroy?id={{ .ID }}">[削除]</a>
{{end}}
</body>
</html>
ファイル:templates/edit.html
todo変更フォーム
<html>
<h1>
</h1>
<form role="form" action="/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>
処理関数を作成する
ファイル:server.go
todoのCRUD処理を行うメインファイル
package main
import (
"github.com/labstack/echo/v4"
"go_echo_todo/models"
"html/template"
"io"
"log"
"net/http"
"strconv"
)
func main() {
e := echo.New()
renderer := &TemplateRenderer{
templates: template.Must(template.ParseGlob("templates/*.html")),
}
e.Renderer = renderer
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
e.GET("/list", list)
e.POST("/create", create)
e.GET("/edit", edit)
e.POST("/update", update)
e.GET("/destroy", destroy)
e.Logger.Fatal(e.Start(":1323"))
}
type TemplateRenderer struct {
templates *template.Template
}
func (t *TemplateRenderer) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
// Add global methods if data is a map
if viewContext, isMap := data.(map[string]interface{}); isMap {
viewContext["reverse"] = c.Echo().Reverse
}
return t.templates.ExecuteTemplate(w, name, data)
}
// delete
func destroy(c echo.Context) error {
id, err := strconv.Atoi(c.QueryParam("id"))
if err != nil {
log.Fatalln(err)
}
models.DeleteTodo(id)
return c.Redirect(http.StatusMovedPermanently, "/list")
}
// update
func update(c echo.Context) error {
id, _ := strconv.Atoi(c.FormValue("id"))
content := c.FormValue("content")
todo, _ := models.GetTodo(id)
todo.Content = content
models.UpdateTodo(todo)
return c.Redirect(http.StatusMovedPermanently, "/list")
}
// edit
func edit(c echo.Context) error {
id, err := strconv.Atoi(c.QueryParam("id"))
if err != nil {
log.Fatalln(err)
}
todo, _ := models.GetTodo(id)
data := map[string]interface{}{
"todo": todo,
}
return c.Render(http.StatusOK, "edit.html", data)
}
// create
func create(c echo.Context) error {
content := c.FormValue("content")
models.CreateTodo(content)
return c.Redirect(http.StatusMovedPermanently, "/list")
}
// list
func list(c echo.Context) error {
var todos []models.Todo
models.Db.Find(&todos)
data := map[string]interface{}{
"todos": todos,
}
return c.Render(http.StatusOK, "list.html", data)
}
実行イメージ
go run server.go
ブラウザで以下を開く
http://localhost:1323/list
以上になります。
ありがとうございました。