教程:使用 go 的 gin 和 gorm 框架来构建 RESTful API 微服务

file

今天我将用 golang 编程语言来为我们的 Todo 应用搭建一套简单的 API。我将会使用 Golang 中简便 / 快捷的 gin-gonic 框架配合用于操作我们数据库,优雅漂亮的 ORM *gorm * 来完成这项工作。要想安装这些包,你应当在工作目录 $GOPATH/src 下运行如下命令:

$ go get github.com/gin-gonic/gin
$ go get -u github.com/jinzhu/gorm
$ go get github.com/go-sql-driver/mysql

在一般的 crud 应用中我们需要如下这样的 API :

  1. POST todos/
  2. GET todos/
  3. GET todos/{id}
  4. PUT todos/{id}
  5. DELETE todos/{id}

我们开始编码吧,去到你的 $GOPATH/src 目录下,创建一个 todo 文件夹。在 todo 文件夹下创建一个名为 main.go 的文件。引入 “gin framework” 到我们的项目中,然后在 main 方法中创建一个类似下面的路由。我比较倾向把 api 前缀写成类似 “api/v1/“ 这样,这就是我们使用 Group 方法的原因。

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()
}

我们已经创建了五个路由,它们对应的功能处理函数类似 createTodo, fetchAllTodo 等这样。接下来我们会讨论它们。

现在我们需要配置数据库连接。使用数据库前需要引入 gorm 和 mysql dialects 2 个软件包。 如下代码:

package main

import (
       "github.com/gin-gonic/gin"
       "github.com/jinzhu/gorm"
       _ "github.com/jinzhu/gorm/dialects/mysql"
)

var db *gorm.DB
func init() {
 //open a db connection
 var err error
 db, err = gorm.Open("mysql", "root:12345@/demo?charset=utf8&parseTime=True&loc=Local")
 if err != nil {
  panic("failed to connect database")
 }
//Migrate the schema
 db.AutoMigrate(&todoModel{})
}

上面代码中 mysql 是数据库驱动,root 是数据库用户名,12345 是密码,demo 则是数据库名称。请修改你的数据库连接信息即可。

接下来我们开始编写建立数据库连接相关的代码。首先我们创建 2 个结构体,命名为 todoModeltransformedTodo ,第一个结构体代表原始的 Todo 数据库字段,第二个结构体用来定义向 api 返回的字段。我们之所以在第二个结构体中重新定义返回的字段主要考虑到数据库中数据的安全性,我们不希望将数据库中的原始字段名(如:updated_at , created_at)直接暴露客户端。

type (
 // 定义原始的数据库字段
 todoModel struct {
  gorm.Model
  Title     string `json:"title"`
  Completed int    `json:"completed"`
 }
// 处理返回的字段
 transformedTodo struct {
  ID        uint   `json:"id"`
  Title     string `json:"title"`
  Completed bool   `json:"completed"`
 }
)

看上述代码有同学可能会有疑问,第一个结构体中多出来一个 gorm.Model 这个额外的字段时表示什么意思呢?好吧,这里我们来解释一下,这个字段将为我们把 IDCreatedAtUpdatedAtDeletedAt 这四个字段嵌入到我们定义好的 todoModel 结构体中,一般数据表中都会用到这四个字段。

Gorm 有迁移工具 ,在调用 ‘init’ 函数初始化的时候已经初始化了。当我们运行应用程序时,它将创建一个连接然后进行迁移。

//迁移 schema
 db.AutoMigrate(&todoModel{})

file

使用 phpmyadmin 可视化工具

你能记得我们前面提到过的五种路由方式吗?现在我们挨个去实现这五种路由方式。

当一个用户用 ‘title 和 completed’ 字段向 ‘api/v1/todos/’ 路径发送一个 PSOT 请求,它将由此路由 ‘v1.POST(「/」,createTodo)‘处理。

接下来让我们继续看一下 createTodo 方法相关的代码书写

// 创建todo
func createTodo(c *gin.Context) {
 completed, _ := strconv.Atoi(c.PostForm("completed"))
 todo := todoModel{Title: c.PostForm("title"), Completed: completed}
 db.Save(&todo)
 c.JSON(http.StatusCreated, gin.H{"status": http.StatusCreated, "message": "Todo item created successfully!", "resourceId": todo.ID})
}

上面的代码中我们使用到了 gin 框架中的 Context 上下文来接收 POST 方式传过来的参数,利用 gorm 连接数据库来保存相关的数据到数据库,之后会给用户返回一个 resourceId

接下来让我们实现剩下的方法

代码已被折叠,点此展开

fetchAllTodo 方法中,我们获取了所有的 todos 并且构建了经过转换的响应体,其中包含 id, title, completed 。我们移除了 CreatedAt, UpdatedAt, DeletedAt 字段并将 int 类型转换为 bool 类型。

到这里基本业务逻辑的代码已经完成,现在让我们试着构建程序并测试它,我将使用 Chrome 的 Postman 扩展来进行测试(你可以使用任何 REST 客户端进行测试,比如 curl)。

要构建应用程序,先打开你的终端,进入项目目录,执行如下命令:

$ go build main.go

上面的命令将构建一个可执行的二进制文件 main ,你可以使用 $ ./main 命令来运行构建号的应用。 哇,我们的 todo 应用现在运行在了本地的 8080 端口了。 它将在终端显示调试日志,因为 gin 默认以 debug 模式运行在 8080 端口。

要测试 API,请先运行 Postman 并依次测试

创建一个 todo:

file

获取 todos 列表:

file

获取单个 todo:

file

更新单个 todo 内容:

file

删除一个 todo:

file

全部的源代码:

代码已被折叠,点此展开

注意:当你使用代码生成时,你必须谨慎操作以下步骤:

  1. 不要从 todos 中查询所有数据,如: select * from todos ,使用分页
  2. 不要相信用户输入,你必须验证输入内容,这里有几种工具来验证输入。 阅读文章 进行验证过程
  3. 检查每个可能的错误
  4. 应根据需要来使用日志和用户认证
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://medium.com/@thedevsaddam/build-r...

译文地址:https://learnku.com/go/t/24598

本帖已被设为精华帖!
本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
讨论数量: 6

你的代码看的我,强迫症都来了

5年前 评论

大佬,咨询下,是不是 api 返回的 json 字段都重新构建一个新的结构体的?因为我最近在写一个 web 应用,感觉有点疑惑,如果一个接口多,返回的结构都不同,是不是都用新的结构体?想过用 map,但是有些数据有点大

5年前 评论
秦穆之 4年前

你的代码看的我,强迫症都来了

5年前 评论
appleboy

不要再用 gopkg.in 來安裝 gin 了

5年前 评论

直接 go get 安装不久好了

4年前 评论
dongguangming

不分 mvc 层吗,直接写到一起了。。。

4年前 评论

你的微服务呢?

4年前 评论