• 用Gin开发Restful


    本章,讲解了如何使用Gin(Gin Web Framework) 开发restful风格的webService Api

    首先,你要确定自己已经十分了解Go基础知识,以及如何驾驭它,否则,请移步 go 基础知识章节

    Gin简化了构建web应用/web服务相关的代码工作,在本章,您将使用Gin路由请求、检索请求详细信息并将JSON封装到响应中.

    在本章中,你将创建具有两个端点的Restful Api,示例项目将是一个关于古典爵士乐记录的数据存储库。

    本章包含下面小节:
    设计API端点.
    创建一个代码文件夹
    创建数据
    编写一个返回所有项目的处理器
    编写一个新增项目的处理器
    编写一个特定项目的处理器

    你可以在google云shell中完成这个教程的所有内容.点击这里<别点了,被墙了>

    先决条件

    • 安装Go1.16以上版本
    • 一个代码编辑器
    • 命令行终端
    • curl工具 Linux和Max已经内置此工具,win10 17063版本亦内置,更早版本的windows,需要你自己去下载

    设计API端点

    设计一个API,它能提供记录在黑胶唱片上的古典音乐,所以,你需要提供一个端点,用来让客户端获取或新增用户专辑

    开发设计API,通常是从设计端点开始,如果这个端点很容易理解,使用你api的人,将更容易成功调用

    你将创建下面两个端点:

    /albums

    • GET ---- 获取专辑列表,以JSON返回
    • POST ---- 添加新专辑,请求数据格式为JSON

    /albums/:id

    • GET ---- 通过ID获取专辑,专辑数据以JSON返回

    创建代码文件夹

    1.2. 分别是在liunx 和windows下如何创建文件夹
    3.创建一个可以管理依赖的模块
      运行 go mod init 命令,将模块路径传给他

    $ go mod init example/web-service-gin
    go: creating new go.mod: module example/web-service-gi

    此命令创建一个go.mod文件,您添加的依赖项将在其中列出以进行跟踪

    接下来,你将设计一个数据结构,用来处理数据

    创建数据

    为保持本教程间接,数据被存到内存里,更常用的做法是,API与数据库交互

    注意,把数据放在内存中的意思是,专辑合集会在你停止服务后丢失.重启服务后,只能重新创建

    编写代码

    在web-service路径下,创建一个名为main.go的文件,
    在mian.go文件内,敲入下面一行代码,用来声明包

    package main

    对于一个单程序(不同于库) 总是在main包中.
    在包声明下方,把album结构体声明拷贝过去,这用来在内存中保存专辑数据
      结构体中的标记 json:"artist" 是标识字段名的,用于结构体内容被序列化成json.如果没有使用标记,那将使用结构体中的大写字母作为json字段名--这种风格通常不常见

    // album represents data about a record album.
    type album struct {
        ID     string  `json:"id"`
        Title  string  `json:"title"`
        Artist string  `json:"artist"`
        Price  float64 `json:"price"`
    }

    4.在结构体声明的下方,粘贴下面album结构体的数据切片,你的梦从这里开始

    // albums slice to seed record album data.
    var albums = []album{
        {ID: "1", Title: "Blue Train", Artist: "John Coltrane", Price: 56.99},
        {ID: "2", Title: "Jeru", Artist: "Gerry Mulligan", Price: 17.99},
        {ID: "3", Title: "Sarah Vaughan and Clifford Brown", Artist: "Sarah Vaughan", Price: 39.99},
    }

    接下来,编写第一个端点代码

    写一个返回所有项目的处理器

    当客户端发起了一个请求GET/albums, 这回把所有专辑信息作为json返回
    为了达到这个目标,你需要做下面的:

    • 准备响应逻辑
    • 将请求路径映射到逻辑的代码

    请注意,这与它们在运行时的执行方式相反,但您首先添加依赖项,然后添加依赖于它们的代码

    编写代码

    粘贴下面代码,获取专辑清单
      getAlbums函数创建了一个从album结构体切片中的 json, 然后把这个json插入响应中

    // getAlbums responds with the list of all albums as JSON.
    func getAlbums(c *gin.Context) {
        c.IndentedJSON(http.StatusOK, albums)
    }

    在这片代码:
    getAlbums函数有一个gin.Context参数,注意,你可以任意命名,----Go和Gin都没有规定函数名称
    在Gin中gin.Context是最常用.它承载了请求的细节,验证和序列化json,等等(尽管名称相似,但这个和Go内置的context包完全不同)
    调用Context.IndextedJSON来把结构体序列化为JSON,然后插入响应
    这个函数的第一个参数是你想发送给客户端的HTTP状态码,此处,你传入了net/http包的StatusOK常量,这标识了 200 ok
    注意,你也可以使用Context.JSON代替Context.IndentedJSON来发送更加复杂的JSON,实际上,在调试阶段Indented形式更容易使用,并且大小差异通常很小。

    2.在main.go文件的顶部附近,粘贴下面代码,将处理函数分配一个端点
    这里把getAlbums处理函数和/albums端点路径做了关联

    func main() {
        router := gin.Default()
        router.GET("/albums", getAlbums)
    
        router.Run("localhost:8080")
    }

    在本片代码:

      • 使用Default初始化Gin路由
      • 使用GET函数来把Http Get方法 和/albums路径处理函数关联,
        注意,你要传入的是,getAlbums函数的名称,这和获取函数结果有很大不同,当你要获取函数结果,你要这么做getAlbums()(注意括号)
      • 使用Run函数,把路由附加到http.server上,并启动服务

    3.在main.go的顶部附件,导入你需要使用的包

    package main
    
    import (
        "net/http"
    
        "github.com/gin-gonic/gin"
    )

    4.保存文件

    运行代码

    1.开始作为依赖项跟踪Gin模块。
    在命令行中,使用go-get添加github.com/gin-gonic/gin模块作为模块的依赖项。使用点参数表示“获取当前目录中代码的依赖项”

    $ go get .
    go get: added github.com/gin-gonic/gin v1.7.2

    Go解析并下载此依赖项,以满足您在上一步中添加的导入声明

    2.在main.go所在目录运行,代码,使用 点 参数,意思是在当前目录下运行代码

    $ go run .

    一旦代码运行,你就拥有了一个Http服务,这样你就能发送请求

    3.另外开一个新的命令行窗口,使用curl能将请求发送给运行中的we服务

    $ curl http://localhost:8080/albums

    这个命令运行后,应该会有下面数据 由服务发送出来

    [
            {
                    "id": "1",
                    "title": "Blue Train",
                    "artist": "John Coltrane",
                    "price": 56.99
            },
            {
                    "id": "2",
                    "title": "Jeru",
                    "artist": "Gerry Mulligan",
                    "price": 17.99
            },
            {
                    "id": "3",
                    "title": "Sarah Vaughan and Clifford Brown",
                    "artist": "Sarah Vaughan",
                    "price": 39.99
            }
    ]

    你已经启动了一个API,在下一节,你将创建另一个端点,目标是,实现一个新增项目的post请求

     编写处理新增项目

    当客户端发起了/albums 的post请求,你想在请求body中添加一个专辑描述到现存的专辑数据中

    为了达到这个目的:
    将新专辑添加到现存清单中
    将post请求和代码路由在一起

    编写代码

    1.添加新专辑到专辑清单中的代码:
      在import段之后,粘贴下面代码(推荐粘贴在文件末尾,不过Go是不强制你声明函数的出现位置)

    // postAlbums adds an album from JSON received in the request body.
    func postAlbums(c *gin.Context) {
        var newAlbum album
    
        // Call BindJSON to bind the received JSON to
        // newAlbum.
        if err := c.BindJSON(&newAlbum); err != nil {
            return
        }
    
        // Add the new album to the slice.
        albums = append(albums, newAlbum)
        c.IndentedJSON(http.StatusCreated, newAlbum)
    }

    本代码:

    • 使用Context.BindJSON来构建请求体到newAlbum.
    • 将初始化后的album结构体传给alums切片
    • 向响应中添加201状态代码,表示您添加的相册的JSON。

    2.修改main函数,以便包含router.post函数,

    func main() {
        router := gin.Default()
        router.GET("/albums", getAlbums)
        router.POST("/albums", postAlbums)
    
        router.Run("localhost:8080")
    }

    将/albums路径上的POST方法与postAlbums函数相关联。

    这片代码:

    • 使用Gin,您可以将处理程序与HTTP方法和路径组合相关联。通过这种方式,您可以根据客户端使用的方法将发送到单个路径的请求单独路由。

    运行代码

    1.如果上一步的服务,没有停止,请先停止
    2.在main.go所在的路径运行,下面的命令

    $ go run .

    3.另开一个命令行窗口,使用curl向你的web服务发送请求

    $ curl http://localhost:8080/albums 
        --include 
        --header "Content-Type: application/json" 
        --request "POST" 
        --data '{"id": "4","title": "The Modern Sound of Betty Carter","artist": "Betty Carter","price": 49.99}'

    这个命令应该返回了json和头文件

    HTTP/1.1 201 Created
    Content-Type: application/json; charset=utf-8
    Date: Wed, 02 Jun 2021 00:34:12 GMT
    Content-Length: 116
    
    {
        "id": "4",
        "title": "The Modern Sound of Betty Carter",
        "artist": "Betty Carter",
        "price": 49.99
    }

    4.与上一节一样,使用curl检索完整的专辑列表,您可以使用该列表确认新专辑已添加。

    $ curl http://localhost:8080/albums 
        --header "Content-Type: application/json" 
        --request "GET"

    应该会显示如下

    [
            {
                    "id": "1",
                    "title": "Blue Train",
                    "artist": "John Coltrane",
                    "price": 56.99
            },
            {
                    "id": "2",
                    "title": "Jeru",
                    "artist": "Gerry Mulligan",
                    "price": 17.99
            },
            {
                    "id": "3",
                    "title": "Sarah Vaughan and Clifford Brown",
                    "artist": "Sarah Vaughan",
                    "price": 39.99
            },
            {
                    "id": "4",
                    "title": "The Modern Sound of Betty Carter",
                    "artist": "Betty Carter",
                    "price": 49.99
            }
    ]

    接下来,你将实现使用GET获得特定的项目

    返回指定项目

    1.在postAlbums下面添加下面代码,检索指定项目
      getAlbumByID函数将提取请求路径的ID,然后匹配定位到的专辑

    // getAlbumByID locates the album whose ID value matches the id
    // parameter sent by the client, then returns that album as a response.
    func getAlbumByID(c *gin.Context) {
        id := c.Param("id")
    
        // Loop over the list of albums, looking for
        // an album whose ID value matches the parameter.
        for _, a := range albums {
            if a.ID == id {
                c.IndentedJSON(http.StatusOK, a)
                return
            }
        }
        c.IndentedJSON(http.StatusNotFound, gin.H{"message": "album not found"})
    }

    本代码中:

    • 使用Context.Param来从url中提取id路径 参数,当你把这个处理函数队友一个路径时,在路径的参数中包含占位符
    • 在切片中轮询album,查找出其ID字段值与ID参数值匹配的,如果找到了,则将该专辑结构序列化为JSON,并使用200 OK HTTP代码作为响应返回
      如前文所述,实际服务可能会使用数据库查询来执行此查找
    • 如果专辑不存在返回HTTP 404错误与HTTP.statusnotfound。

    2.最后,修改main函数,以便让他包含router.GET,

    func main() {
        router := gin.Default()
        router.GET("/albums", getAlbums)
        router.GET("/albums/:id", getAlbumByID)
        router.POST("/albums", postAlbums)
    
        router.Run("localhost:8080")
    }

    本代码中:

    • 将/albums/:id路径与getAlbumByID函数相关联。在Gin中,路径中项目前面的冒号表示该项目是路径参数。

    运行代码:

    1.如果服务一直运行,停止他
    2.在main.go 运行命令行

    $ go run .

    3.使用curl请求web服务

    $ curl http://localhost:8080/albums/2

    该命令应显示您所使用ID的专辑JSON。如果找不到专辑,您将获得带有错误消息的JSON。

    {
            "id": "2",
            "title": "Jeru",
            "artist": "Gerry Mulligan",
            "price": 17.99
    }

    总结

    恭喜,刚刚使用Go和Gin编写了一个简单的RESTful web服务。

    建议下一个主题:
    如果你是Go的新手,你将在Go本质论和如何写go代码 能发现最好的教程
    Go之旅 是最好的基础知识
    更多关于Gin,看看Gin web框架包文档 或者 Gin Web框架文档

    完整代码

    package main
    
    import (
        "net/http"
    
        "github.com/gin-gonic/gin"
    )
    
    // album represents data about a record album.
    type album struct {
        ID     string  `json:"id"`
        Title  string  `json:"title"`
        Artist string  `json:"artist"`
        Price  float64 `json:"price"`
    }
    
    // albums slice to seed record album data.
    var albums = []album{
        {ID: "1", Title: "Blue Train", Artist: "John Coltrane", Price: 56.99},
        {ID: "2", Title: "Jeru", Artist: "Gerry Mulligan", Price: 17.99},
        {ID: "3", Title: "Sarah Vaughan and Clifford Brown", Artist: "Sarah Vaughan", Price: 39.99},
    }
    
    func main() {
        router := gin.Default()
        router.GET("/albums", getAlbums)
        router.GET("/albums/:id", getAlbumByID)
        router.POST("/albums", postAlbums)
    
        router.Run("localhost:8080")
    }
    
    // getAlbums responds with the list of all albums as JSON.
    func getAlbums(c *gin.Context) {
        c.IndentedJSON(http.StatusOK, albums)
    }
    
    // postAlbums adds an album from JSON received in the request body.
    func postAlbums(c *gin.Context) {
        var newAlbum album
    
        // Call BindJSON to bind the received JSON to
        // newAlbum.
        if err := c.BindJSON(&newAlbum); err != nil {
            return
        }
    
        // Add the new album to the slice.
        albums = append(albums, newAlbum)
        c.IndentedJSON(http.StatusCreated, newAlbum)
    }
    
    // getAlbumByID locates the album whose ID value matches the id
    // parameter sent by the client, then returns that album as a response.
    func getAlbumByID(c *gin.Context) {
        id := c.Param("id")
    
        // Loop through the list of albums, looking for
        // an album whose ID value matches the parameter.
        for _, a := range albums {
            if a.ID == id {
                c.IndentedJSON(http.StatusOK, a)
                return
            }
        }
        c.IndentedJSON(http.StatusNotFound, gin.H{"message": "album not found"})
    }
  • 相关阅读:
    CSS学习笔记(二)选择器
    CSS学习笔记(九)对列表应用样式和创建导航条
    在Eclipse中用远程svn资源库创建项目并提交和更新
    CSS学习笔记(六)圆角框
    CSS学习笔记(五)背景图基础
    SVN创建资源库和远程连接配置
    Struts2标签中支持OGNL表达式的热计算及带参数的<s:a>链接
    php处理字符串格式的计算公式
    CSS学习笔记(十)对表单和数据表格使用样式
    CSS学习笔记(三)层叠和特殊性
  • 原文地址:https://www.cnblogs.com/yaoshi641/p/15246892.html
Copyright © 2020-2023  润新知