Gin框架与《Web Development with Go》实
与Mongodb有关的数据持久
taskmanager2项目中的目录结构:
taskmaanger-data2.png
src/taskmanager2/data2/taskRepository.go
其中的内容为与mongodb中的集合task紧密相关的CRUD操作
package data2
import (
"time"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"taskmanager2/models2"
)
type TaskRepository struct {
C *mgo.Collection
}
func (r *TaskRepository) Create(task *models2.Task) error {
obj_id := bson.NewObjectId()
task.Id = obj_id
task.CreatedOn = time.Now()
task.Status = "Created"
err := r.C.Insert(&task)
return err
}
func (r *TaskRepository) Update(task *models2.Task) error {
// partial update on MogoDB
err := r.C.Update(bson.M{"_id": task.Id},
bson.M{"$set": bson.M{
"name": task.Name,
"description": task.Description,
"due": task.Due,
"status": task.Status,
"tags": task.Tags,
}})
return err
}
func (r *TaskRepository) Delete(id string) error {
err := r.C.Remove(bson.M{"_id": bson.ObjectIdHex(id)})
return err
}
func (r *TaskRepository) GetAll() []models2.Task {
var tasks []models2.Task
iter := r.C.Find(nil).Iter()
result := models2.Task{}
for iter.Next(&result) {
tasks = append(tasks, result)
}
return tasks
}
func (r *TaskRepository) GetById(id string) (task models2.Task, err error) {
err = r.C.FindId(bson.ObjectIdHex(id)).One(&task)
return
}
func (r *TaskRepository) GetByUser(user string) []models2.Task {
var tasks []models2.Task
iter := r.C.Find(bson.M{"createdby": user}).Iter()
result := models2.Task{}
for iter.Next(&result) {
tasks = append(tasks, result)
}
return tasks
}
task资源的处理函数
资源路径与其对应的处理函数:
src/taskmanager2/routers2/task.go
package routers2
import (
"gopkg.in/gin-gonic/gin.v1"
"taskmanager2/controllers2"
"taskmanager2/common2"
)
// SetTaskRoutes configures routes for task entity
func SetTaskRoutes(router *gin.Engine) *gin.Engine {
taR := router.Group("/tm2/tasks")
taR.Use(common2.Authorize())
{
taR.POST("", controllers2.CreateTask)
taR.PUT(":id", controllers2.UpdateTask)
taR.DELETE(":id", controllers2.DeleteTask)
taR.GET("", controllers2.GetTasks)
taR.GET("t/:id/", controllers2.GetTaskByID)
taR.GET("users/:email/", controllers2.GetTasksByUser)
}
return router
}
具体函数:
src/taskmanager2/controllers2/taskCtrler.go
package controllers2
import (
"net/http"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"gopkg.in/gin-gonic/gin.v1"
"taskmanager2/common2"
"taskmanager2/data2"
)
// CreateTask insert a new Task document
// Handler for HTTP Post - "/tasks
func CreateTask(c *gin.Context) {
var dataResource TaskResource
// Decode the incoming Task json
err := c.BindJSON(&dataResource)
if err != nil {
common2.DisplayAppError(
c,
err,
"Invalid Task data",
500,
)
return
}
task := &dataResource.Data
context := NewContext()
defer context.Close()
context.User = task.CreatedBy
col := context.DbCollection("tasks")
repo := &data2.TaskRepository{C: col}
// Insert a task document
repo.Create(task)
c.JSON(http.StatusCreated, TaskResource{Data: *task})
}
// GetTasks returns all Task document
// Handler for HTTP Get - "/tasks"
func GetTasks(c *gin.Context) {
context := NewContext()
defer context.Close()
col := context.DbCollection("tasks")
repo := &data2.TaskRepository{C: col}
tasks := repo.GetAll()
c.JSON(http.StatusOK, TasksResource{Data: tasks})
}
// GetTaskByID returns a single Task document by id
// Handler for HTTP Get - "/tasks/t/:id"
func GetTaskByID(c *gin.Context) {
// Get id from the incoming url
id := c.Param("id")
context := NewContext()
defer context.Close()
col := context.DbCollection("tasks")
repo := &data2.TaskRepository{C: col}
task, err := repo.GetById(id)
if err != nil {
if err == mgo.ErrNotFound {
c.JSON(http.StatusNoContent, gin.H{})
} else {
common2.DisplayAppError(
c,
err,
"An unexpected error has occurred",
500,
)
}
return
}
c.JSON(http.StatusOK, TaskResource{Data: task})
}
// GetTasksByUser returns all Tasks created by a User
// Handler for HTTP Get - "/tasks/users/:email"
func GetTasksByUser(c *gin.Context) {
// Get id from the incoming url
user := c.Param("email")
context := NewContext()
defer context.Close()
col := context.DbCollection("tasks")
repo := &data2.TaskRepository{C: col}
tasks := repo.GetByUser(user)
c.JSON(http.StatusOK, TasksResource{Data: tasks})
}
// UpdateTask update an existing Task document
// Handler for HTTP Put - "/tasks/:id"
func UpdateTask(c *gin.Context) {
// Get id from the incoming url
id := bson.ObjectIdHex(c.Param("id"))
var dataResource TaskResource
// Decode the incoming Task json
err := c.BindJSON(&dataResource)
if err != nil {
common2.DisplayAppError(
c,
err,
"Invalid Task data",
500,
)
return
}
task := &dataResource.Data
task.Id = id
context := NewContext()
defer context.Close()
col := context.DbCollection("tasks")
repo := &data2.TaskRepository{C: col}
// Update an existing Task document
if err := repo.Update(task); err != nil {
common2.DisplayAppError(
c,
err,
"An unexpected error has occurred",
500,
)
return
}
c.Status(http.StatusNoContent)
}
// DeleteTask deelete an existing Task document
// Handler for HTTP Delete - "/tasks/:id"
func DeleteTask(c *gin.Context) {
id := c.Param("id")
context := NewContext()
defer context.Close()
col := context.DbCollection("tasks")
repo := &data2.TaskRepository{C: col}
// Delete an existing Task document
err := repo.Delete(id)
if err != nil {
common2.DisplayAppError(
c,
err,
"An unexpected error has occurred",
500,
)
return
}
c.Status(http.StatusNoContent)
}
json资源模型
src/taskmanager2/controllers2/resources.go
package controllers2
import (
"taskmanager2/models2"
)
type (
...
TaskResource struct {
Data models2.Task `json:"data"`
}
TasksResource struct {
Data []models2.Task `json:"data"`
}
...
)
task资源的测试API操作
登录系统并获取jwt
post --- localhost:8890/tm2/users/login
调用:
响应:
增加数据
post --- localhost:8890/tm2/tasks/
调用:
响应:
数据库中查看结果:
删除数据
delete --- localhost:8890/tm2/tasks/593e72625a9c4078ae5f1a79
调用:
响应:
数据库中查看结果(第14条数据已被删除):
修改数据
put --- localhost:8890/tm2/tasks/593e72495a9c4078ae5f1a78
调用:
响应:
tm-p2.png
数据库中查看结果:
原数据:
新数据:
获取全部的数据
get --- localhost:8890/tm2/tasks
调用:
响应:
通过task的id获取数据
get --- localhost:8890/tm2/tasks/t/593e6f985a9c4078ae5f1a77/
调用:
响应:
通过user的email获取数据
get --- localhost:8890/tm2/tasks/users/007@abc.com
调用:
响应:
小结
至此,RESTful API中,user和task资源的功能已全部实现。实践证明gin框架能够很好地满足此应用的改造要求。
在改造的过程中,某些细节之处仍有不足,待日后慢慢完善。