美文网首页Go语言我用 LinuxGo
如何使用 Gin 和 Gorm 搭建一个简单的 API 服务 (

如何使用 Gin 和 Gorm 搭建一个简单的 API 服务 (

作者: blackpiglet | 来源:发表于2018-03-14 14:37 被阅读430次
    gin-gonic

      这是系列文章的第二篇。下面是另外两篇的链接:
      如何使用 Gin 和 Gorm 搭建一个简单的 API 服务(一)
      如何使用 Gin 和 Gorm 搭建一个简单的 API 服务(三)

    创建 API

      我们之前已经跑过 Gin 框架的代码,现在是时候加些功能进去了。

    读取全部信息

      我们先从"增删改查"中的"查"入手,查询我们之前添加的信息。我接下来要删除几行代码,并把 Gin 的框架代码加回来。

    package main
    
    import (
            "fmt"
            "github.com/gin-gonic/gin"
            "github.com/jinzhu/gorm"
            _ "github.com/jinzhu/gorm/dialects/sqlite"
    )
    
    var db *gorm.DB
    var err error
    
    type Person struct {
            ID        uint   `json:"id”`
            FirstName string `json:"firstname”`
            LastName  string `json:"lastname”`
    }
    
    func main() {
            // NOTE: See we’re using = to assign the global var
            // instead of := which would assign it only in this function
            db, err = gorm.Open("sqlite3", "./gorm.db")
            if err != nil {
                    fmt.Println(err)
            }
            defer db.Close()
            db.AutoMigrate(&Person{})
            r := gin.Default()
            r.GET("g/", GetProjects)
            r.Run("g:8080")
    }
    
    func GetProjects(c *gin.Context) {
            var people []Person
            if err := db.Find(&people).Error; err != nil {
                    c.AbortWithStatus(404)
                    fmt.Println(err)
            } else {
                    c.JSON(200, people)
            }
    }
    

      那么运行程序,并在浏览器中访问 http://localhost:8080,你应该看到:

    [{“id”: 1,”firstname”: “John”,”lastname”: “Doe”}]
    

      喔,几行代码我们就可以拿到 API 服务器的响应了,而且大部分代码都是用来错误处理的。

    读取特定信息

      好,为了把 API 接口写的更符合 REST 规范,我们加入查询特定信息的借口

    package main
    
    import (
        "fmt"
        "github.com/gin-gonic/gin"
        "github.com/jinzhu/gorm"
        _ "github.com/jinzhu/gorm/dialects/sqlite"
    )
    
    var db *gorm.DB
    var err error
    
    type Person struct {
        ID        uint   `json:"id”`
        FirstName string `json:"firstname”`
        LastName  string `json:"lastname”`
    }
    
    func main() {
        // NOTE: See we’re using = to assign the global var
        // instead of := which would assign it only in this function
        db, err = gorm.Open("sqlite3", "./gorm.db")
        if err != nil {
            fmt.Println(err)
        }
        defer db.Close()
        db.AutoMigrate(&Person{})
        r := gin.Default()
    
        r.GET("g/", GetProjects)
        r.GET("/people/:id", GetPerson)
    
        r.Run("g:8080")
    }
    
    func GetProjects(c *gin.Context) {
        var people []Person
        if err := db.Find(&people).Error; err != nil {
            c.AbortWithStatus(404)
            fmt.Println(err)
        } else {
            c.JSON(200, people)
        }
    }
    
    func GetPerson(c *gin.Context) {
        id := c.Params.ByName("id")
        var person Person
        if err := db.Where("id = ?", id).First(&person).Error; err != nil {
            c.AbortWithStatus(404)
            fmt.Println(err)
        } else {
            c.JSON(200, person)
        }
    }
    

      现在运行程序,但请注意,如果要访问全部信息,你需要访问的地址变成了 http://localhost:8080/people/ ,如果 在 URL 的末尾加入了 ID,你就会得到特定的信息 http://localhost:8080/people/1

    {"id": 1, "firstname": "John", "lastname": "Doe"}
    

    添加信息

      只有一条记录是看不大出来查询全部信息和查询单条信息的区别的,所以咱们来把添加信息的功能加上吧。

    package main
    
    import (
        "fmt"
        "github.com/gin-gonic/gin"
        "github.com/jinzhu/gorm"
        _ "github.com/jinzhu/gorm/dialects/sqlite"
    )
    
    var db *gorm.DB
    var err error
    
    type Person struct {
        ID        uint   `json:"id”`
        FirstName string `json:"firstname”`
        LastName  string `json:"lastname”`
    }
    
    func main() {
        // NOTE: See we’re using = to assign the global var
        // instead of := which would assign it only in this function
        db, err = gorm.Open("sqlite3", "./gorm.db")
        if err != nil {
            fmt.Println(err)
        }
        defer db.Close()
        db.AutoMigrate(&Person{})
        r := gin.Default()
    
        r.GET("g/", GetProjects)
        r.GET("/people/:id", GetPerson)
        r.POST("/people", CreatePerson)
    
        r.Run("g:8080")
    }
    
    func GetProjects(c *gin.Context) {
        var people []Person
        if err := db.Find(&people).Error; err != nil {
            c.AbortWithStatus(404)
            fmt.Println(err)
        } else {
            c.JSON(200, people)
        }
    }
    
    func GetPerson(c *gin.Context) {
        id := c.Params.ByName("id")
        var person Person
        if err := db.Where("id = ?", id).First(&person).Error; err != nil {
            c.AbortWithStatus(404)
            fmt.Println(err)
        } else {
            c.JSON(200, person)
        }
    }
    
    func CreatePerson(c *gin.Context) {
        var person Person
        c.BindJSON(&person)
        db.Create(&person)
        c.JSON(200, person)
    }
    

      接下来让我们从终端运行 curl 命令测试一下新加的功能是不是可用,当然还是先要把程序运行起来。
      在终端运行:

    $ curl -i -X POST http://localhost:8080/people -d '{ "FirstName": "Elvis", "LastName": "Presley"}'
    

      应该会看到成功的响应消息:

    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8
    Date: Sat, 03 Dec 2016 00:14:06 GMT
    Content-Length: 50
    {"id":2,"firstname":"Elvis","lastname":"Presley"}
    

      现在我们访问一下查询全部信息的接口,http://localhost:8080/people/

    [{"id": 1,"firstname": "John","lastname": "Doe"},{"id": 2,"firstname": "Elvis","lastname": "Presley"}]
    

      太棒啦,代码没问题。这回我们只发送 Person 结构体的部分信息,看看程序会如何处理。

    $ curl -i -X POST http://localhost:8080/people -d '{ "FirstName": "Madison"}'
    

      刷新一下浏览器,发现只添加了我们发送的信息。

    [{"id": 1,"firstname": "John","lastname": "Doe"},{"id": 2,"firstname": "Elvis","lastname": "Presley"},{"id": 3,"firstname": "Madison","lastname": ""}]
    

      这就是 Gin 如何工作的了,留意一下 c.BindJSON(&person) 这行,它会自动匹配请求消息中的数据信息。
      虽然请求消息里可能缺某些信息,就比如刚才那个例子,而且大小写不匹配也没有关系,Gin 的容错性非常高。非常简单!

    更新信息

      我们不能把 Madison 这条记录没有姓氏啊,是时候加入更新功能了。

    package main
    
    import (
        "fmt"
        "github.com/gin-gonic/gin"
        "github.com/jinzhu/gorm"
        _ "github.com/jinzhu/gorm/dialects/sqlite"
    )
    
    var db *gorm.DB
    var err error
    
    type Person struct {
        ID        uint   `json:"id"`
        FirstName string `json:"firstname"`
        LastName  string `json:"lastname"`
    }
    
    func main() {
        // NOTE: See we're using = to assign the global var
        // instead of := which would assign it only in this function
        db, err = gorm.Open("sqlite3", "./gorm.db")
        if err != nil {
            fmt.Println(err)
        }
        defer db.Close()
        db.AutoMigrate(&Person{})
        r := gin.Default()
    
        r.GET("g/", GetProjects)
        r.GET("/people/:id", GetPerson)
        r.POST("/people", CreatePerson)
        r.PUT("/people/:id", UpdatePerson)
    
        r.Run("g:8080")
    }
    
    func GetProjects(c *gin.Context) {
        var people []Person
        if err := db.Find(&people).Error; err != nil {
            c.AbortWithStatus(404)
            fmt.Println(err)
        } else {
            c.JSON(200, people)
        }
    }
    
    func GetPerson(c *gin.Context) {
        id := c.Params.ByName("id")
        var person Person
        if err := db.Where("id = ?", id).First(&person).Error; err != nil {
            c.AbortWithStatus(404)
            fmt.Println(err)
        } else {
            c.JSON(200, person)
        }
    }
    
    func CreatePerson(c *gin.Context) {
        var person Person
        c.BindJSON(&person)
        db.Create(&person)
        c.JSON(200, person)
    }
    
    func UpdatePerson(c *gin.Context) {
        var person Person
        id := c.Params.ByName("id")
        if err := db.Where("id = ?", id).First(&person).Error; err != nil {
            c.AbortWithStatus(404)
            fmt.Println(err)
        }
        c.BindJSON(&person)
        db.Save(&person)
        c.JSON(200, person)
    }
    

      这次我们用类似的 curl 命令 进行测试,但不同的是用 PUT 方法,而且是用在特定的信息上。

    $ curl -i -X PUT http://localhost:8080/people/3 -d '{ "FirstName": "Madison", "LastName":"Sawyer" }'
    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8
    Date: Sat, 03 Dec 2016 00:25:35 GMT
    Content-Length: 51
    {"id":3,"firstname":"Madison","lastname":"Sawyer"}
    

      当然更新浏览器后,我们就可以看见 "sawyer" 添加到了 "LastName" 一栏里。

    [{"id": 1,"firstname": "John","lastname": "Doe"},{"id": 2,"firstname": "Elvis","lastname": "Presley"},{"id": 3,"firstname": "Madison","lastname": "Sawyer"}]
    

      这次我们只更新 "FirstName" 字段试试。

    $ curl -i -X PUT http://localhost:8080/people/3 -d '{ "FirstName": "Tom" }'
    

      显示如下

    [{"id": 1,"firstname": "John","lastname": "Doe"},{"id": 2,"firstname": "Elvis","lastname": "Presley"},{"id": 3,"firstname": "Tom","lastname": "Sawyer"}]
    

    删除

      这次轮到删除功能了

    package main
    
    import (
        "fmt"
        "github.com/gin-gonic/gin"
        "github.com/jinzhu/gorm"
        _ "github.com/jinzhu/gorm/dialects/sqlite"
    )
    
    var db *gorm.DB
    var err error
    
    type Person struct {
        ID        uint   `json:"id"`
        FirstName string `json:"firstname"`
        LastName  string `json:"lastname"`
    }
    
    func main() {
        // NOTE: See we're using = to assign the global var
        // instead of := which would assign it only in this function
        db, err = gorm.Open("sqlite3", "./gorm.db")
        if err != nil {
            fmt.Println(err)
        }
        defer db.Close()
        db.AutoMigrate(&Person{})
        r := gin.Default()
    
        r.GET("g/", GetProjects)
        r.GET("/people/:id", GetPerson)
        r.POST("/people", CreatePerson)
        r.PUT("/people/:id", UpdatePerson)
        r.DELETE("/people/:id", DeletePerson)
    
        r.Run("g:8080")
    }
    
    func GetProjects(c *gin.Context) {
        var people []Person
        if err := db.Find(&people).Error; err != nil {
            c.AbortWithStatus(404)
            fmt.Println(err)
        } else {
            c.JSON(200, people)
        }
    }
    
    func GetPerson(c *gin.Context) {
        id := c.Params.ByName("id")
        var person Person
        if err := db.Where("id = ?", id).First(&person).Error; err != nil {
            c.AbortWithStatus(404)
            fmt.Println(err)
        } else {
            c.JSON(200, person)
        }
    }
    
    func CreatePerson(c *gin.Context) {
        var person Person
        c.BindJSON(&person)
        db.Create(&person)
        c.JSON(200, person)
    }
    
    func UpdatePerson(c *gin.Context) {
        var person Person
        id := c.Params.ByName("id")
        if err := db.Where("id = ?", id).First(&person).Error; err != nil {
            c.AbortWithStatus(404)
            fmt.Println(err)
        }
        c.BindJSON(&person)
        db.Save(&person)
        c.JSON(200, person)
    }
    
    func DeletePerson(c *gin.Context) {
        id := c.Params.ByName("id")
        var person Person
        d := db.Where("id = ?", id).Delete(&person)
        fmt.Println(d)
        c.JSON(200, gin.H{"id #" + id: "deleted"})
    }
    

      我们用 curl 的 Delete 方法测试一下

    $ curl -i -X DELETE http://localhost:8080/people/1
    
    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8
    Date: Sat, 03 Dec 2016 00:32:40 GMT
    Content-Length: 20
    
    {"id #1":"deleted"}
    

      刷新浏览器,John Doe 这条记录已经删掉了。

    [{"id": 2,"firstname": "Elvis","lastname": "Presley"},{"id": 3,"firstname": "Tom","lastname": "Sawyer"}]
    

    相关文章

      网友评论

      本文标题:如何使用 Gin 和 Gorm 搭建一个简单的 API 服务 (

      本文链接:https://www.haomeiwen.com/subject/rorfqftx.html