Developing a RESTful API with Go and Gin

Developing a RESTful API with Go and Gin

本教程介绍了使用 Go 和Gin Web 框架(Gin) 编写 RESTful Web 服务 API 的基础知识。

如果您对 Go 及其工具有基本的了解,您将从本教程中获得最大收益。如果这是您第一次接触 Go,请参阅 教程:Go 入门以 获得快速介绍。

Gin 简化了许多与构建 Web 应用程序(包括 Web 服务)相关的编码任务。在本教程中,您将使用 Gin 来路由请求、检索请求详细信息以及编组 JSON 以获取响应。

在本教程中,您将构建一个具有两个端点的 RESTful API 服务器。您的示例项目将是有关老式爵士乐唱片的数据存储库。

a restful api

设计 API 端点。

为您的代码创建一个文件夹。

创建数据。

编写一个处理程序以返回所有项目。

编写一个处理程序来添加一个新项目。

编写一个处理程序来返回一个特定的项目。

要尝试将此作为您在 Google Cloud Shell 中完成的交互式教程,请单击下面的按钮。

设计 API 端点

您将构建一个 API,该 API 可让您访问出售老式黑胶唱片的商店。因此,您需要提供端点,客户端可以通过这些端点为用户获取和添加相册。

在开发 API 时,您通常从设计端点开始。如果端点易于理解,您的 API 用户将获得更大的成功。

以下是您将在本教程中创建的端点。

/专辑

GET– 获取所有专辑的列表,以 JSON 形式返回。

POST– 从作为 JSON 发送的请求数据中添加新专辑。

/专辑/:id

GET– 通过 ID 获取专辑,将专辑数据作为 JSON 返回。

接下来,您将为代码创建一个文件夹。

为您的代码创建一个文件夹

$ mkdir web-service-gin

$ cd web-service-gin

创建一个模块,您可以在其中管理依赖项

go mod init example/web-service-gin

go: 

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

创建数据

为了使教程简单,您将数据存储在内存中。更典型的 API 将与数据库交互。

请注意,将数据存储在内存中意味着每次停止服务器时,相册集都会丢失,然后在启动时重新创建。

编写代码

使用您的文本编辑器,编辑器用vs code,在 web-service 目录中创建一个名为 main.go 的文件。您将在此文件中编写您的 Go 代码。

进入 main.go,在文件顶部,粘贴以下包声明。

package main

独立程序(与库相反)始终位于 package 中main。

在包声明下,粘贴以下 album结构声明。您将使用它在内存中存储专辑数据。

结构标记,例如json:"artist"指定当结构的内容被序列化为 JSON 时字段的名称应该是什么。如果没有它们,JSON 将使用结构的大写字段名称——这种风格在 JSON 中并不常见。

type album struct {ID string `json:"id"`Title string `json:"title"`Artist string `json:"artist"`Price float64 `json:"price"`}

在您刚刚添加的结构声明下,粘贴以下 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 参数的函数。请注意,你可以给这个函数起任何名字——Gin 和 Go 都不需要特定的函数名格式。

gin.Context是金酒最重要的部分。它携带请求详细信息、验证和序列化 JSON 等。(尽管名称相似,但这与 Go 的内置 context包不同。)

调用Context.IndentedJSON 以将结构序列化为 JSON 并将其添加到响应中。

该函数的第一个参数是您要发送给客户端的 HTTP 状态代码。在这里,您StatusOK 从包中传递常量net/http来指示200 OK.

请注意,您可以替换 为发送更紧凑的 JSONContext.IndentedJSON的调用 。Context.JSON在实践中,缩进形式在调试时更容易使用,并且大小差异通常很小。

在 main.go 顶部附近,就在albumsslice 声明的下方,粘贴下面的代码以将处理函数分配给端点路径。

这会建立一个关联,在该关联中getAlbums处理对 /albums端点路径的请求。

func main() {

router := gin.Default()

router.GET("/albums", getAlbums)

router.Run("localhost:8080")

}


使用 初始化 Gin 路由器 Default。

使用该GET 函数将GETHTTP 方法和/albums路径与处理函数相关联。

请注意,您正在传递函数的名称。getAlbums这与传递函数的结果不同,您可以通过传递来完成getAlbums()(注意括号)。

使用该Run 功能将路由器连接到http.Server并启动服务器。

在 main.go 顶部附近,就在包声明的下方,导入您需要支持您刚刚编写的代码的包。

第一行代码应如下所示:

package main

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

保存 main.go。

运行代码

开始跟踪 Gin 模块作为依赖项。

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

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

解决并下载此依赖项以满足import 您在上一步中添加的声明。

从包含 main.go 的目录中的命令行,运行代码。使用点参数表示“在当前目录中运行代码”。

$ go run .

代码运行后,您就有了一个正在运行的 HTTP 服务器,您可以向其发送请求。

在新的命令行窗口中,用于curl向正在运行的 Web 服务发出请求。

$ 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添加项目的请求。

编写处理程序以添加新项目

当客户端在 发出POST请求时/albums,您希望将请求正文中描述的相册添加到现有相册的数据中。


将新专辑添加到现有列表的逻辑。

将请求路由POST到您的逻辑的一些代码。

编写代码

添加代码以将专辑数据添加到专辑列表。

在语句之后的某处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将从 JSON 初始化的结构附加到albums 切片。

201向响应添加状态代码,以及表示您添加的专辑的 JSON。

更改您的main函数,使其包含该router.POST函数,如下所示。

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

在此代码中,您:

将路径中的POST方法与 函数相关联。/albumspostAlbums

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

运行代码

如果服务器从上一节开始仍在运行,请停止它。

从包含 main.go 的目录中的命令行,运行代码。

$ go run .

从不同的命令行窗口,用于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 CreatedContent-Type: application/json; charset=utf-8Date: Wed, 02 Jun 2021 00:34:12 GMTContent-Length: 116{"id": "4","title": "The Modern Sound of Betty Carter","artist": "Betty Carter","price": 49.99}

与上一节一样,使用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特定项目的 a。

编写处理程序以返回特定项目

当客户端向 发出请求时GET /albums/[id],您希望返回 ID 与id路径参数匹配的相册。

为此,您将:

添加逻辑以检索请求的相册。

将路径映射到逻辑。

编写代码

在您在上一节中添加的函数下方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"})}

在此代码中,您:

用于从 URLContext.Param 中检索id路径参数。当您将此处理程序映射到路径时,您将在路径中包含参数的占位符。

循环album切片中的结构,寻找其ID 字段值与id参数值匹配的结构。如果找到,则将该album结构序列化为 JSON,并将其作为带有200 OK HTTP 代码的响应返回。

如上所述,现实世界的服务可能会使用数据库查询来执行此查找。

如果找不到专辑,则返回 HTTP404错误。http.StatusNotFound

最后,更改您的main,使其包含对 的新调用router.GET,路径现在/albums/:id为 ,如以下示例所示。

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 中,路径中项目前面的冒号表示该项目是路径参数。

运行代码

如果服务器从上一节开始仍在运行,请停止它。

在包含 main.go 的目录中的命令行中,运行代码以启动服务器。

$ go run .

从不同的命令行窗口,用于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 服务。

你可能感兴趣的:(Developing a RESTful API with Go and Gin)