zoukankan      html  css  js  c++  java
  • 如何使用 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"}]
    
     
     
     
     



    作者:blackpiglet
    链接:https://www.jianshu.com/p/443766f0e796
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    centos8 将SSSD配置为使用LDAP并要求TLS身份验证
    Centos8 搭建 kafka2.8 .net5 简单使用kafka
    .net core 3.1 ActionFilter 拦截器 偶然 OnActionExecuting 中HttpContext.Session.Id 为空字符串 的问题
    Springboot根据不同环境加载对应的配置
    VMware Workstation12 安装 Centos8.3
    .net core json配置文件小结
    springboot mybatisplus createtime和updatetime自动填充
    .net core autofac依赖注入简洁版
    .Net Core 使用 redis 存储 session
    .Net Core 接入 RocketMQ
  • 原文地址:https://www.cnblogs.com/brady-wang/p/13074149.html
Copyright © 2011-2022 走看看