iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 29
2

RESTful API服務

使用Go語言建立一個待辦清單的API,其功能為新增、更新、查詢和刪除待辦事項,API框架使用的是gin-goni,後端使用mongodb。

需要安裝Go語言的第三方Library

go get github.com/gin-gonic/gin
go get github.com/globalsign/mgo

MongoDB使用docker容器,需要安裝docker

brew install docker

總共創建API接口如下:

  • POST todos/ :新增TODO清單
  • GET todos/ :查詢所有的TODO列表
  • GET todos/{id} :查詢單一TODO事件
  • PUT todos/{id} :更新單一TODO事件
  • DELETE todos/{id} :聞除單一TODO事件

初始化路由

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()
    v1 := router.Group("/api/v1/todos")
    {
        v1.POST("/", createTodo)
        v1.GET("/", fetchAllTodo)
        v1.GET("/:id", fetchSingleTodo)
        v1.PUT("/:id", updateTodo)
        v1.DELETE("/:id", deleteTodo)
    }
    router.Run()
}

todoModel

const保存的是MongoDB的位置,因為是本地端測試用,所以IP為127.0.0.1,MongoDB的預設端口為27017
宣告一個todoModel的結構體,下面實作其他的API方法。

const (
    db         = "ToDo"
    collection = "ToDoList"
    host       = "127.0.0.1:27017"
)

var globalS *mgo.Session

type (
    todoModel struct {
        Title     string    `bson:"title" json:"title"`
        Completed int       `bson:"completed" json:"completed"`
        CreatedAt time.Time `bson:"createdAt" json:"createdAt"`
    }

    transformedTodo struct {
        ID        string    `bson:"_id" json:"id"`
        Title     string    `bson:"title" json:"title"`
        Completed bool      `bson:"completed" json:"completed"`
        CreatedAt time.Time `bson:"createdAt" json:"createdAt"`
    }
)

func init() {
    globalS, err := mgo.Dial(host)
    if err != nil {
        log.Fatal(err)
    }

}

createTodo

從 gin 獲取 POST 的數據,並寫入到DB裡,執行成功時返回對應的todo.ID

func createTodo(c *gin.Context) {
    completed, _ := strconv.Atoi(c.PostForm("completed"))
    todo := todoModel{
        ID:        bson.NewObjectId().Hex(),
        Title:     c.PostForm("title"),
        Completed: completed,
        CreatedAt: time.Now(),
    }

    ms := globalS.Copy()
    mc := ms.DB(db).C(collection)
    defer ms.Close()
    mc.Insert(todo)
    c.JSON(http.StatusCreated, gin.H{"status": http.StatusCreated,
        "message": "Todo item created successfully!", "resourceId": todo.ID})
}

fetchAllTodo

    var todos []todoModel
    var _todos []transformedTodo

    ms := globalS.Copy()
    mc := ms.DB(db).C(collection)
    defer ms.Close()
    mc.Find(nil).All(&todos)
    if len(todos) <= 0 {
        c.JSON(http.StatusNotFound, gin.H{"status": http.StatusNotFound, "message": "No todo found!!"})
        return
    }
    for _, item := range todos {
        completed := false
        if item.Completed == 1 {
            completed = true
        } else {
            completed = false
        }
        _todos = append(_todos, transformedTodo{ID: item.ID, Title: item.Title, Completed: completed, CreatedAt: time.Now()})
    }
    c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": _todos})
}

fetchSingleTodo

func fetchSingleTodo(c *gin.Context) {
    var todo todoModel
    id := c.Param("id")
    ms := globalS.Copy()
    mc := ms.DB(db).C(collection)
    mc.FindId(id)
    if todo.ID == "" {
        c.JSON(http.StatusNotFound, gin.H{"status": http.StatusNotFound, "message": "No todo found!"})
        return
    }
    completed := false
    if todo.Completed == 1 {
        completed = true
    } else {
        completed = false
    }
    _todo := transformedTodo{ID: todo.ID, Title: todo.Title, Completed: completed, CreatedAt: todo.CreatedAt}
    c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "data": _todo})
}

updateTodo

func updateTodo(c *gin.Context) {
    var todo todoModel
    id := c.Param("id")
    ms := globalS.Copy()
    mc := ms.DB(db).C(collection)
    defer ms.Close()
    mc.FindId(id).One(&todo)
    if todo.ID == "" {
        c.JSON(http.StatusNotFound, gin.H{"status": http.StatusNotFound, "message": "No todo found!"})
        return
    }
    todo.Title = c.PostForm("title")
    todo.Completed, _ = strconv.Atoi(c.PostForm("completed"))

    mc.UpdateId(id, todo)
    c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "message": "Todo update successfully!"})
}

deleteTodo

func deleteTodo(c *gin.Context) {
    var todo todoModel
    id := c.Param("id")
    ms := globalS.Copy()
    mc := ms.DB(db).C(collection)
    defer ms.Close()
    mc.FindId(id).One(&todo)
    if todo.ID == "" {
        c.JSON(http.StatusNotFound, gin.H{"status": http.StatusNotFound, "message": "No todo found!"})
        return
    }
    mc.RemoveId(id)
    c.JSON(http.StatusOK, gin.H{"status": http.StatusOK, "message": "Todo deleted successfully!"})
}

API運行與測試

運行

go run main.go
# 使用 Docker 啟動 mongoDB 容器
docker run --name mongo -d mongo

測試

使用 postman 測試API服務是否正常

  • createTodo
    https://ithelp.ithome.com.tw/upload/images/20191014/20120698ymb1yXSm8g.jpg
  • fetchSingleTodo
    https://ithelp.ithome.com.tw/upload/images/20191014/20120698oyv27x1l84.jpg
  • deleteTodo
    https://ithelp.ithome.com.tw/upload/images/20191014/20120698kwSLTPoFrk.jpg

上一篇
Day28 項目實戰(2)
下一篇
Day30 學完Go語言之後的起跑點
系列文
Golang入門到進階實戰30

尚未有邦友留言

立即登入留言