教程:使用 Go 和 Gin 開發 RESTful API

本教程介紹使用 Go 和Gin Web 框架(Gin)編寫 RESTful Web 服務 API 的基礎知識。

如果您對 Go 及其工具有基本的瞭解,您將從本教程中獲得最大收益。

如果這是您第一次接觸 Go,請參閱教程:Go 入門以獲取快速介紹。

Gin 簡化了與構建 Web 應用程式(包括 Web 服務)相關的許多編碼任務。

在本教程中,您將使用 Gin 來路由請求、檢索請求詳細資訊並編組 JSON 以獲取響應。

在本教程中,您將構建一個具有兩個端點的 RESTful API 伺服器。您的示例專案將是有關復古爵士樂唱片的資料儲存庫。

本教程包括以下部分:

設計 API 路徑。

為您的程式碼建立一個資料夾。

建立資料。

編寫一個處理程式來返回所有專案。

編寫一個處理程式來新增一個新專案。

編寫一個處理程式來返回一個特定的專案。

注意:

有關其他教程,請參閱教程。

先決條件

Go 1.16 或更高版本的安裝。

有關安裝說明,請參閱安裝 Go。

一種編輯程式碼的工具。

您擁有的任何文字編輯器都可以正常工作。

命令終端。

Go 適用於 Linux 和 Mac 上的任何終端,以及 Windows 中的 PowerShell 或 cmd。

curl工具。

在 Linux 和 Mac 上,這應該已經安裝了。在 Windows 上,它包含在 Windows 10 Insider build 17063 及更高版本中。對於較早的 Windows 版本,您可能需要安裝它。有關更多資訊,請參閱Tar 和 Curl 來到 Windows。

設計 API

您將構建一個 API,該 API 提供對銷售黑膠唱片老式唱片商店的訪問。

因此,您需要提供url,客戶端可以透過這些url為使用者獲取和新增專輯。

在開發 API 時,您通常從設計url開始。如果路徑易於理解,您的 API 使用者將獲得更多成功。

以下是您將在本教程中建立的端點。

/albums

– 獲取所有專輯的列表,以 JSON 形式返回。

– 從以 JSON 形式傳送的請求資料中新增新專輯。

/albums/:id

– 透過 ID 獲取專輯,以 JSON 形式返回專輯資料。

接下來,您將為您的程式碼建立一個資料夾。

為您的程式碼建立一個資料夾

首先,為您將編寫的程式碼建立一個專案。

開啟命令提示符並切換到您的主目錄。

在 Linux 或 Mac 上:

$ cd

在 Windows 上:

C:\> cd %HOMEPATH%

使用命令提示符為您的程式碼建立一個名為 web-service-gin 的目錄。

$ 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

此命令建立一個 go。mod 檔案,您新增的依賴項將在其中列出以進行跟蹤。有關使用模組路徑命名模組的更多資訊,請參閱管理依賴項。

接下來,您將設計用於處理資料的資料結構。

建立資料

為使本教程簡單,您將資料儲存在記憶體中。更典型的 API 會與資料庫互動。

請注意,將資料儲存在記憶體中意味著每次停止伺服器時專輯集都會丟失,然後在啟動時重新建立。

編寫程式碼

使用您的文字編輯器,在 web-service 目錄中建立一個名為 main。go 的檔案。您將在此檔案中編寫 Go 程式碼。

在 main。go 檔案的頂部,貼上以下包宣告。

package main

獨立程式(與庫相對)始終在 package 中。

在包宣告下方,貼上以下結構宣告 。您將使用它在記憶體中儲存專輯資料。

結構標記,例如指定當結構的內容序列化為 JSON 時欄位的名稱應該是什麼。如果沒有它們,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”`

}

在您剛剛新增的結構宣告下方,貼上以下結構片段, 其中包含您將用於啟動的資料。

// albums slice to seed record album data。

var albums = []album{

}

接下來,您將編寫程式碼來實現您的第一個介面。

編寫一個處理程式來返回所有專案

當客戶端在 發出請求時,您希望以 JSON 形式返回所有專輯。

為此,您將編寫以下內容:

準備響應的邏輯

將請求路徑對映到邏輯的程式碼

請注意,這與它們在執行時的執行方式相反,但您首先新增依賴項,然後新增依賴它們的程式碼。

編寫程式碼

在上一節中新增的結構體程式碼下,貼上以下程式碼以獲取專輯列表。

此函式從結構切片建立 JSON ,將 JSON 寫入響應。

// getAlbums responds with the list of all albums as JSON。

func getAlbums(c *gin。Context) {

c。IndentedJSON(http。StatusOK, albums)

}

在此程式碼中,您:

編寫一個帶引數的函式 。請注意,您可以為該函式指定任何名稱——Gin 和 Go 都不需要特定的函式名稱格式。

是Gin最重要的部分。它攜帶請求詳細資訊、驗證和序列化 JSON 等。(儘管名稱相似,但這與 Go 的內建包不同。)

呼叫以將結構序列化為 JSON 並將其新增到響應中。

該函式的第一個引數是您要傳送給客戶端的 HTTP 狀態程式碼。在這裡,您從包中傳遞常量以指示。

請注意,您可以替換 為傳送更緊湊的 JSON的呼叫。在實踐中,縮排形式在除錯時更容易使用,並且大小差異通常很小。

在 main。go 的頂部附近,就在slice宣告的下方,貼上下面的程式碼以將處理程式函式分配給介面路徑。

這會建立一個關聯,在該關聯中處理對端點路徑的請求 。

func main() {

router := gin。Default()

router。GET(“/albums”, getAlbums)

router。Run(“localhost:8080”)

}

在此程式碼中,您:

使用。

使用該函式將HTTP 方法和路徑與處理程式函式相關聯。

請注意,你傳遞的名稱的的功能。這與傳遞函式的結果不同,傳遞函式是傳遞(注意括號)。

使用功能將路由器連線到一個並啟動伺服器。

在 main。go 的頂部附近,就在包宣告的下方,匯入支援剛剛編寫的程式碼所需的包。

第一行程式碼應該是這樣的:

package main

import (

“net/http”

“github。com/gin-gonic/gin”

儲存 main。go。

執行程式碼

您已經啟動了一個 API!在下一部分中,您將使用程式碼建立另一個url來處理新增專案的請求。

編寫一個處理程式來新增一個新專案

當客戶端在 處發出請求時,您希望將請求正文中描述的專輯新增到現有專輯資料中。

為此,您將編寫以下內容:

將新專輯新增到現有列表的邏輯。

將請求路由到您的邏輯的一些程式碼。

編寫程式碼

新增程式碼以將專輯資料新增到專輯列表中。

在語句之後的某處貼上以下程式碼。(檔案的末尾是這段程式碼的好地方,但 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)

}

在此程式碼中,您:

使用請求體結合。

將從 JSON 初始化的結構附加到slice。

向響應新增狀態程式碼,以及表示您新增的專輯的 JSON。

更改您的函式,使其包含該函式,如下所示。

func main() {

router := gin。Default()

router。GET(“/albums”, getAlbums)

router。POST(“/albums”, postAlbums)

router。Run(“localhost:8080”)

}

在此程式碼中,您:

將路徑中的方法與函式相關聯。

使用 Gin,您可以將處理程式與 HTTP 方法和路徑組合相關聯。透過這種方式,您可以根據客戶端使用的方法單獨路由傳送到單個路徑的請求。

執行程式碼

如果伺服器從上一節開始仍在執行,請停止它。

從包含 main。go 的目錄中的命令列,執行程式碼。

$ go run 。

從不同的命令列視窗,用於向正在執行的 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

}

與上一節一樣,使用檢索專輯的完整列表,您可以使用它來確認新專輯已新增。

$ 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

}

在下一部分中,您將新增程式碼來處理特定專案。

編寫處理程式以返回特定專案

當客戶端向 發出請求時,您希望返回 ID 與path 引數匹配的相簿。

為此,您將:

新增邏輯以檢索請求的專輯。

將路徑對映到邏輯。

編寫程式碼

在您在上一節中新增的函式下方,貼上以下程式碼以檢索特定專輯。

該函式將提取請求路徑中的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”})

}

在此程式碼中,您:

用於從 URL檢索路徑引數。當您將此處理程式對映到路徑時,您將在路徑中包含引數的佔位符。

迴圈切片中的結構,查詢欄位值與引數值匹配的結構。如果找到,則將該結構序列化為JSON 並將其作為帶有HTTP 程式碼的響應返回。

如上所述,現實世界的服務可能會使用資料庫查詢來執行此查詢。

如果找不到專輯,則返回 HTTP錯誤。

最後,更改您的使其包含對 的新呼叫,路徑現在為,如以下示例所示。

func main() {

router := gin。Default()

router。GET(“/albums”, getAlbums)

router。GET(“/albums/:id”, getAlbumByID)

router。POST(“/albums”, postAlbums)

router。Run(“localhost:8080”)

}

在此程式碼中,您:

將路徑與函式關聯。在 Gin 中,路徑中專案前面的冒號表示該專案是路徑引數。

執行程式碼

如果伺服器從上一節開始仍在執行,請停止它。

從包含 main。go 的目錄中的命令列,執行程式碼以啟動伺服器。

$ go run 。

從不同的命令列視窗,用於向正在執行的 Web 服務發出請求。

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

該命令應顯示您使用其 ID 的專輯的 JSON。如果未找到專輯,您將收到帶有錯誤訊息的 JSON。

{

“id”: “2”,

“title”: “Jeru”,

“artist”: “Gerry Mulligan”,

“price”: 17。99

}

結論

恭喜!您剛剛使用 Go 和 Gin 編寫了一個簡單的 RESTful 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{

}

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

}

TAG: albums程式碼JSONALBUM專輯