RESTful API

EST即表述性状态传递(英文:Representational State Transfer,简称REST),它是一种针对网络应用的设计和开发方式,能够升高开发的复杂性,进步零碎的可伸缩性。(援用自百度百科)。

HTTP Method

  1. 早在 HTTP 0.9 版本中,只有一个GET办法,该办法是一个幂等办法,用于获取服务器上的资源;
  2. HTTP 1.0 版本中又减少了HEAD和POST办法,其中罕用的是 POST 办法,个别用于给服务端提交一个资源。
  3. HTTP1.1 版本的时,又减少了几个办法。总共加起来有9个。
    它们的作用:
  4. GET 办法可申请一个指定资源的示意模式,应用 GET 的申请应该只被用于获取数据。
  5. HEAD 办法用于申请一个与 GET 申请的响应雷同的响应,但没有响应体。
  6. POST 办法用于将实体提交到指定的资源,通常导致服务器上的状态变动或副作用。
  7. PUT 办法用于申请有效载荷替换指标资源的所有以后示意。
  8. DELETE 办法用于删除指定的资源。
  9. CONNECT 办法用于建设一个到由指标资源标识的服务器的隧道。
  10. OPTIONS 办法用于形容指标资源的通信选项。
  11. TRACE 办法用于沿着到指标资源的门路执行一个音讯环回测试。
  12. PATCH 办法用于对资源利用局部批改。

在 RESTful API 中,应用的次要是以下五种 HTTP 办法:

  • GET,示意读取服务器上的资源;
  • POST,示意在服务器上创立资源;
  • PUT,示意更新或者替换服务器上的资源;
  • DELETE,示意删除服务器上的资源;
  • PATCH,示意更新 / 批改资源的一部分。

一个简略的 RESTful API

Golang 提供了内置的 net/http 包,用来解决这些 HTTP 申请,能够比拟不便地开发一个 HTTP 服务。

示例:

package mainimport (    "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 mainimport (    "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 mainimport (    "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 的办法引入即可:

  1. 下载安装 Gin 框架
    go get -u github.com/gin-gonic/gin
  2. 在 Go 语言代码中导入应用
    import "github.com/gin-gonic/gin"

应用 Gin 框架

咱们应用 Gin 框架来重写下面的示例:

package mainimport "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。