Go 通關:RESTful API 服務,急速入門!
RESTful API
EST 即表述性狀態傳遞(英文:Representational State Transfer,簡稱 REST),它是一種針對網絡應用的設計和開發方式,可以降低開發的複雜性,提高系統的可伸縮性。(引用自百度百科)。
HTTP Method
-
早在 HTTP 0.9 版本中,只有一個 GET 方法,該方法是一個冪等方法,用於獲取服務器上的資源;
-
HTTP 1.0 版本中又增加了 HEAD 和 POST 方法,其中常用的是 POST 方法,一般用於給服務端提交一個資源。
-
HTTP1.1 版本的時,又增加了幾個方法。總共加起來有 9 個。
它們的作用:
-
「GET」 方法可請求一個指定資源的表示形式,使用 GET 的請求應該只被用於獲取數據。
-
「HEAD」 方法用於請求一個與 GET 請求的響應相同的響應,但沒有響應體。
-
「POST」 方法用於將實體提交到指定的資源,通常導致服務器上的狀態變化或副作用。
-
「PUT」 方法用於請求有效載荷替換目標資源的所有當前表示。
-
「DELETE」 方法用於刪除指定的資源。
-
「CONNECT」 方法用於建立一個到由目標資源標識的服務器的隧道。
-
「OPTIONS」 方法用於描述目標資源的通信選項。
-
「TRACE」 方法用於沿着到目標資源的路徑執行一個消息環回測試。
-
「PATCH」 方法用於對資源應用部分修改。
在 RESTful API 中,使用的主要是以下五種 HTTP 方法:
-
GET,表示讀取服務器上的資源;
-
POST,表示在服務器上創建資源;
-
PUT,表示更新或者替換服務器上的資源;
-
DELETE,表示刪除服務器上的資源;
-
PATCH,表示更新 / 修改資源的一部分。
一個簡單的 RESTful API
Golang 提供了內置的 net/http 包,用來處理這些 HTTP 請求,可以比較方便地開發一個 HTTP 服務。
示例:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/users",handleUsers)
http.ListenAndServe(":8080", nil)
}
func handleUsers(w http.ResponseWriter, r *http.Request){
fmt.Fprintln(w,"ID:1,Name:張三")
fmt.Fprintln(w,"ID:2,Name:李四")
fmt.Fprintln(w,"ID:3,Name:王五")
}
運行程序後,在瀏覽器中輸入 http://localhost:8080/users, 就可以看到如下內容信息:
ID:1,Name:張三
ID:2,Name:李四
ID:3,Name:王五
示例中,不光可以用 GET 能進行訪問,POST、PUT 等也可以,接下來對示例進行改進,使它使它符合 RESTful API 的規範:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/users",handleUsers)
http.ListenAndServe(":8080", nil)
}
func handleUsers(w http.ResponseWriter, r *http.Request){
switch r.Method {
case "GET":
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w,"ID:1,Name:張三")
fmt.Fprintln(w,"ID:2,Name:李四")
fmt.Fprintln(w,"ID:3,Name:王五")
default:
w.WriteHeader(http.StatusNotFound)
fmt.Fprintln(w,"not found")
}
}
我們在 handleUsers 函數中增加了只在使用 GET 方法時,才獲得所有用戶的信息,其他情況返回 not found。
RESTful JSON API
在項目接口中,數據大多數情況下會使用 json 格式來傳輸,再次對示例進行改造,使它返回 json 格式的內容:
package main
import (
"encoding/json"
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/users",handleUsers)
http.ListenAndServe(":8080", nil)
}
//數據源,模擬MySQL中的數據
var users = []User{
{ID: 1,Name: "張三"},
{ID: 2,Name: "李四"},
{ID: 3,Name: "王五"},
}
func handleUsers(w http.ResponseWriter, r *http.Request){
switch r.Method {
case "GET":
users,err:=json.Marshal(users)
if err!=nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprint(w,"{\"message\": \""+err.Error()+"\"}")
}else {
w.WriteHeader(http.StatusOK)
w.Write(users)
}
default:
w.WriteHeader(http.StatusNotFound)
fmt.Fprint(w,"{\"message\": \"not found\"}")
}
}
//用戶
type User struct {
ID int
Name string
}
運行結果:
[{"ID":1,"Name":"張三"},{"ID":2,"Name":"李四"},{"ID":3,"Name":"王五"}]
這次,我們新建了一個 User 結構體,使用 users 這個切片存儲所有的用戶,然後在 handleUsers 函數中把它轉化爲一個 JSON 數組返回。
Gin 框架
上面我們使用的是 Go 語言自帶的 net/http 包,寫法比較簡單,但是它也有許多不足之處:
-
不能單獨地對請求方法(POST、GET 等)註冊特定的處理函數;
-
不支持 Path 變量參數;
-
不能自動對 Path 進行校準;
-
性能一般,擴展性不足;
-
……
基於以上的不足,我們可以使用其它的 Golang Web 框架,例如今天要介紹的 Gin 框架。
引入 Gin 框架
Gin 框架是一個在 Github 上開源的 Web 框架,它封裝了很多 Web 開發需要的功能,而且性能也非常高,可以很容易地寫出 RESTful API。
Gin 框架其實是一個模塊,採用 Go Mod 的方法引入即可:
-
下載安裝 Gin 框架
go get -u github.com/gin-gonic/gin
-
在 Go 語言代碼中導入使用
import "github.com/gin-gonic/gin"
使用 Gin 框架
我們使用 Gin 框架來重寫上面的示例:
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/users", listUser)
r.Run(":8080")
}
func listUser(c *gin.Context) {
c.JSON(200, users)
}
//數據源,模擬MySQL中的數據
var users = []User{
{ID: 1, Name: "張三"},
{ID: 2, Name: "李四"},
{ID: 3, Name: "王五"},
}
//用戶
type User struct {
ID int
Name string
}
對比 net/http 包,Gin 框架的代碼非常簡單,通過 GET 方法就可以創建一個只處理 HTTP GET 方法的服務,且使用 c.JSON 方法便可輸出 JSON 格式的數據。
通過 Run 方法啓動 HTTP 服務,監聽 8080 端口。運行這個 Gin 示例,在瀏覽器中輸入 http://localhost:8080/users,可以看到和通過 net/http 包實現的效果是一樣的。
獲取一個用戶
獲取一個用戶的信息,我們使用 GET 方法,設計的 URL 格式爲 :
http://localhost:8080/users/1
url 中的數字 1 爲用戶 id,我們通過 id 來獲取一個指定的用戶:
func main() {
//省略其它沒有改動過的代碼
r.GET("/users/:id", getUser)
}
func getUser(c *gin.Context) {
id := c.Param("id")
var user User
found := false
//類似於數據庫的SQL查詢
for _, u := range users {
if strings.EqualFold(id, strconv.Itoa(u.ID)) {
user = u
found = true
break
}
}
if found {
c.JSON(200, user)
} else {
c.JSON(404, gin.H{
"message": "用戶不存在",
})
}
}
在 Gin 框架中,路徑中使用冒號表示 Path 路徑參數,比如示例中的 :id,然後通過 c.Param("id") 獲取需要查詢用戶的 ID 值。
運行示例,訪問地址 http://localhost:8080/users/1
,便可以獲取 ID 爲 1 的用戶:{"ID":1,"Name":"張三"}
新增一個用戶
新增一個用戶的 URL 格式爲:
http://localhost:8080/users
向這個 URL 發送數據,就可以新增一個用戶.
func main() {
//省略其它沒有改動過的代碼
r.POST("/users", createUser)
}
func createUser(c *gin.Context) {
name := c.DefaultPostForm("name", "")
if name != "" {
u := User{ID: len(users) + 1, Name: name}
users = append(users, u)
c.JSON(http.StatusCreated,u)
} else {
c.JSON(http.StatusOK, gin.H{
"message": "請輸入用戶名稱",
})
}
}
新增用戶的邏輯是獲取客戶端上傳的 name 值,然後生成一個 User 用戶,最後把它存儲到 users 集合中。
我們使用 curl 命令發送一個新增用戶請求:
curl -X POST -d 'name=無塵' http://localhost:8080/users
{"ID":4,"Name":"無塵"}
可以看到,新增用戶成功,且返回了新增的用戶及分配的 ID。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/bWlczebW1Ihcw5P0FlWFTA