k8s APIServer依賴的go-restful WebService框架的簡單使用

jemygraw發表於2018-09-14

在 K8S 的 APIServer 的程式碼中,依賴了一個叫做 go-restful 的庫來構建 HTTP 的 API。 在學習 K8S 的程式碼過程中,我們要對這個庫做些瞭解,這樣才能更加方便地知道 APIServer 的 Restful 服務是如何構建的。 這個專案在 Github 上面的地址是:https://github.com/emicklei/go-restful 。我們也很容易地找到了作者的一篇介紹使用方法的部落格。 帖子的地址在:http://ernestmicklei.com/2012/11/go-restful-first-working-example/

這裡我們將它簡單翻譯一下,幫助大家學習。下面的內容是譯文。


在前面的一個帖子裡面,我介紹了用 Google 的 Go 語言開發的,用來構建 REST 風格 WebService 的包 go-restful 的設計。 今天,我完成了這個包的實現,包含如下的功能:

  1. 使用 Route 來建立 WebService,Route 是 HTTP Request 到 Go 函式的對映。
  2. 每個 Route 都需要的資訊包括 HTTP 請求方法(GET,POST,...),URL 路徑(/users),MimeType以及其繫結的處理函式。
  3. 處理函式的輸入包括一個 Request 和一個 Response。
  4. Request 物件用來獲取 Path 和 Query引數,Headers以及 Request Body(XML,JSON,...)。
  5. Response 物件用來設定 Status,Headers,以及 Response Body
  6. Request 和 Response 物件都可以使用標準庫來在物件和XML或JSON之間進行轉換。

我們可以使用一個簡單的例子來演示上面的過程。一個用來對User 物件進行 CRUD 操作的 WebService。 我們首先在一個 userservice 目錄裡面建立一個 userservice.go 檔案。

package userservice

import (
    "github.com/emicklei/go-restful"
    "log"
)

type User struct {
    Id, Name string
}

User 型別代表我們要操作的物件。

檔案中的下一個部分就是 WebService 的 API 定義。這些 API 是一組Route物件的集合,這些Route定義瞭如何將進來的 HTTP 請求對映到對應的處理函式。

func New() *restful.WebService {
    service := new(restful.WebService)
    service.
        Path("/users").
        Consumes(restful.MIME_XML, restful.MIME_JSON).
        Produces(restful.MIME_XML, restful.MIME_JSON)

    service.Route(service.GET("/{user-id}").To(FindUser))
    service.Route(service.POST("").To(UpdateUser))
    service.Route(service.PUT("/{user-id}").To(CreateUser))
    service.Route(service.DELETE("/{user-id}").To(RemoveUser))

    return service
}

首先,使用一個 root URL 來初始化所有路徑的 service,定義每個 Route 可以接收的MIME型別,以及可以響應的MIME型別。當然這個也可以針對每個Route單獨指定。然後,service 指定它可以提供哪些路徑。這裡的函式呼叫 GET("/{user-id}")Method("GET").Path("/{user-id}") 的簡單寫法,這個方法呼叫建立一個 RouteBuilder 物件。然後使用這個 RouteBuilder 物件指定對應的處理函式。

下面,就是定義每個 Route 的處理函式了。

func FindUser(request *restful.Request, response *restful.Response) {
    id := request.PathParameter("user-id")
    // here you would fetch user from some persistence system
    usr := &User{Id: id, Name: "John Doe"}
    response.WriteEntity(usr)
}

Route 的處理函式的方法宣告都一樣,包含一個 Restful 的 Request 和 Response,兩個一對。 Request 是 http Request 物件的封裝,提供了一些方便的方法。Response 是對 http ResponseWriter 的封裝。這種設計方式可以將底層的 HTTP 結構開放給開發者,同時也為開發者提供了一些通用的 Restful 函式,例如 WriteEntity。WriteEntity 函式會檢查請求的 Accept 頭部來決定 response 的 Content-Type 頭部,同時也決定了使用那種方法來序列化物件(這裡就是 User 物件)。

userservice.go 檔案的其他內容就是剩下的Route處理函式的定義。

func UpdateUser(request *restful.Request, response *restful.Response) {
    usr := new(User)
    err := request.ReadEntity(&usr)
    // here you would update the user with some persistence system
    if err == nil {
        response.WriteEntity(usr)
    } else {
        response.WriteError(http.StatusInternalServerError,err)
    }
}

func CreateUser(request *restful.Request, response *restful.Response) {
    usr := User{Id: request.PathParameter("user-id")}
    err := request.ReadEntity(&usr)
    // here you would create the user with some persistence system
    if err == nil {
        response.WriteEntity(usr)
    } else {
        response.WriteError(http.StatusInternalServerError,err)
    }
}

func RemoveUser(request *restful.Request, response *restful.Response) {
    // here you would delete the user from some persistence system
}

現在,我們已經完成了 UserService 的定義和實現。下面的程式碼段演示瞭如何在一個應用中使用這個 service。

package main

import (
    "github.com/emicklei/go-restful"
    "log"
    "net/http"
    "userservice"
)

func main() {
    restful.Add(userservice.New())
    log.Fatal(http.ListenAndServe(":8080", nil))
}

服務啟動之後,我們可以利用下面的方法測試:

  1. 預設的請求
$ curl http://localhost:8080/users/12
<?xml version="1.0" encoding="UTF-8"?>
 <User>
  <Id>12</Id>
  <Name>John Doe</Name>
 </User>
  1. 帶 Accpet 頭部的請求
$ curl http://localhost:9090/users/12 -H 'Accept: application/json'
{
 "Id": "12",
 "Name": "John Doe"
}
  1. 新建一個User物件
$ curl http://localhost:9090/users -X POST -d '{"Id":"32","Name":"jemygraw"}' -H 'Content-Type: application/json'
<?xml version="1.0" encoding="UTF-8"?>
 <User>
  <Id>32</Id>
  <Name>jemygraw</Name>
 </User>
  1. 新的一個User物件,要求返回JSON。
$ curl http://localhost:9090/users -X POST -d '{"Id":"32","Name":"jemygraw"}' -H 'Content-Type: application/json' -H 'Accept: application/json'
{
 "Id": "32",
 "Name": "jemygraw"
}

譯者:

本文永久儲存地址為:https://github.com/jemygraw/TechDoc/blob/master/Go%E5%BA%93%E5%AD%A6%E4%B9%A0/2018-09-14%20k8s%20%E4%BE%9D%E8%B5%96%E5%BA%93%E4%B8%AD%E7%9A%84go-restful%E6%A1%86%E6%9E%B6.md

相關文章