Treasure2018 2日目 Golang
Treasure2018 2 日目
今日は Golang 入門 2 日目
やったこと
簡単な Web アプリを Golang で書けることが出来た 🎉🎉
TODO アプリの拡張。
SQL を叩いて Golang でパースすることが出来ました。
わからなかったところ
最後の TODO アプリの検索の仕方で手間取りました。
title と status で検索したかったけど、片方だけの検索しか出来なかった。
title と status の同時検索が出来なかった。
curl http://localhost:8080/api/todos/search?title=test\&completed=0
controller/task.go
ファイル
package controller import ( "encoding/json" "net/http" "github.com/voyagegroup/go-todo/model" "github.com/jmoiron/sqlx" ) // Todo はTodoへのリクエストに関する制御をします type Todo struct { DB *sqlx.DB } // GetはDBからユーザを取得して結果を返します func (t *Todo) Get(w http.ResponseWriter, r *http.Request) error { todos, err := model.TodosAll(t.DB) if err != nil { return err } return JSON(w, 200, todos) } func (t *Todo) Put(w http.ResponseWriter, r *http.Request) error { var todo model.Todo if err := json.NewDecoder(r.Body).Decode(&todo); err != nil { return err } if err := TXHandler(t.DB, func(tx *sqlx.Tx) error { result, err := todo.Update(tx) if err != nil { return err } if err := tx.Commit(); err != nil { return err } todo.ID, err = result.LastInsertId() return err }); err != nil { return err } return JSON(w, http.StatusOK, todo) } // PostはタスクをDBに追加します // todoをJSONとして受け取ることを想定しています。 func (t *Todo) Post(w http.ResponseWriter, r *http.Request) error { var todo model.Todo if err := json.NewDecoder(r.Body).Decode(&todo); err != nil { return err } if err := TXHandler(t.DB, func(tx *sqlx.Tx) error { result, err := todo.Insert(tx) if err != nil { return err } if err := tx.Commit(); err != nil { return err } todo.ID, err = result.LastInsertId() return err }); err != nil { return err } return JSON(w, http.StatusCreated, todo) } func (t *Todo) Delete(w http.ResponseWriter, r *http.Request) error { var todo model.Todo if err := json.NewDecoder(r.Body).Decode(&todo); err != nil { return err } if err := TXHandler(t.DB, func(tx *sqlx.Tx) error { _, err := todo.Delete(tx) if err != nil { return err } return tx.Commit() }); err != nil { return err } return JSON(w, http.StatusOK, todo) } func (t *Todo) Toggle(w http.ResponseWriter, r *http.Request) error { var todo model.Todo if err := json.NewDecoder(r.Body).Decode(&todo); err != nil { return err } if err := TXHandler(t.DB, func(tx *sqlx.Tx) error { _, err := todo.Toggle(tx) if err != nil { return err } return tx.Commit() }); err != nil { return err } return JSON(w, http.StatusOK, todo) } func (t *Todo) Search(w http.ResponseWriter, r *http.Request) error { title := r.URL.Query().Get("title") completed := r.URL.Query().Get("completed") todo, err := model.SearchByCompleted(t.DB, completed) if err != nil { return err } return JSON(w, http.StatusOK, todo) }
model/task.go
ファイル
package model import ( "database/sql" "time" "github.com/jmoiron/sqlx" ) // Todoは管理するタスク type Todo struct { ID int64 `db:"todo_id" json:"id"` Title string `json:"title"` Completed bool `json:"completed"` Created *time.Time `json:"created"` Updated *time.Time `json:"updated"` } func TodosAll(dbx *sqlx.DB) (todos []Todo, err error) { if err := dbx.Select(&todos, "select * from todos"); err != nil { return nil, err } return todos, nil } func TodoOne(dbx *sqlx.DB, id int64) (*Todo, error) { var todo Todo if err := dbx.Get(&todo, ` select * from todos where todo_id = ? `, id); err != nil { return nil, err } return &todo, nil } // TodosToggleAllは全部のtoggleのステータスをトグルします func TodosToggleAll(tx *sqlx.Tx, checked bool) (sql.Result, error) { stmt, err := tx.Prepare(` update todos set completed = ? `) if err != nil { return nil, err } defer stmt.Close() return stmt.Exec(checked) } func (t *Todo) Update(tx *sqlx.Tx) (sql.Result, error) { stmt, err := tx.Prepare(` update todos set title = ? where todo_id = ? `) if err != nil { return nil, err } defer stmt.Close() return stmt.Exec(t.Title, t.ID) } func (t *Todo) Insert(tx *sqlx.Tx) (sql.Result, error) { stmt, err := tx.Prepare(` insert into todos (title, completed) values(?, ?) `) if err != nil { return nil, err } defer stmt.Close() return stmt.Exec(t.Title, t.Completed) } // Toggle は指定されたタスクについて現在の状態と入れ替えます。 func (t *Todo) Toggle(tx *sqlx.Tx) (sql.Result, error) { stmt, err := tx.Prepare(` update todos set completed=? where todo_id=? `) if err != nil { return nil, err } defer stmt.Close() return stmt.Exec(!t.Completed, t.ID) } func (t *Todo) Delete(tx *sqlx.Tx) (sql.Result, error) { stmt, err := tx.Prepare(`delete from todos where todo_id = ?`) if err != nil { return nil, err } defer stmt.Close() return stmt.Exec(t.ID) } // TodosDeleteAllはすべてのタスクを消去します。 func TodosDeleteAll(tx *sqlx.Tx) (sql.Result, error) { stmt, err := tx.Prepare(`delete from todos where completed = 1`) if err != nil { return nil, err } defer stmt.Close() return stmt.Exec() } func SearchByTitle(dbx *sqlx.DB, title string) ([]*Todo, error) { var todos []*Todo if err := dbx.Select(&todos, "select * from todos where title = ?", title); err != nil { return nil, err } return todos, nil } func SearchByCompleted(dbx *sqlx.DB, completed string) ([]*Todo, error) { var todos []*Todo if err := dbx.Select(&todos, "select * from todos where completed = ?", completed); err != nil { return nil, err } return todos, nil }
server.go
に以下を追記
router.Handle("/api/todos/search", handler(todo.Search)).Methods("GET")
memo
SQL の使い方は以下の URL を参考にする。
https://github.com/go-sql-driver/mysql/wiki/Examples
http://go-database-sql.org/accessing.html