Go で API を作るときは実際にサーバを起動して HTTP で叩くテストを作りたいので HTTP で叩くのを簡単にする自分用ツール。認証を回避できない環境で Swagger とか POSTMAN を手作業でAuth通して叩くのは面倒なので Go Test 上で認証して叩くことができる。おまけでレスポンスの Unmarshalもできる。GitHubはここ。
いつでもAPIが叩けると精神衛生上良いし、フロントからエラー報告が来た時もすぐ検証ができる。
GitHub にアクセスできない仕事場が稀に良く有るので貼り付けさせてください。
使い方
// ここまで省略。 Server を起動しておいてから以下を実行するテストコードを書く。
// サーバー接続情報を作る
k := Knocker{"127.0.0.1", 8080, ""}
// シンプルな Get ただし認証が通らない。b は res.Body の文字列
t.Run("Required authorization token not found", func(t *testing.T) {
res, b, err := k.Knock(http.MethodGet, "/private", nil, nil)
if err != nil {
panic(err)
}
assert.Equal(t, 401, res.StatusCode)
assert.Equal(t, b, "Required authorization token not found\n")
})
// 認証を通してから Get
t.Run("Auth and OK", func(t *testing.T) {
res, _, err := k.Auth(http.MethodGet, "/auth", nil)
if err != nil {
panic(err)
}
// レスポンスの中身が検証しやすいように Unmarshal する機能が入っている。
v := &PrivateResponse{}
res, _, err = k.Knock(http.MethodGet, "/private", nil, v)
if err != nil {
panic(err)
}
assert.Equal(t, 200, res.StatusCode)
assert.Equal(t, v.Tag, "Go")
})
// 略
// Private api サーバ側でレスポンスを作っているコード
var private = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
reply:= PrivateResponse{
Title: "jwt token が無いとアクセスできないはず",
Tag: "Go",
}
json.NewEncoder(w).Encode(reply)
})
// Private Response サーバ側のレスポンス構造体。テストからそのまま参照して使う。
type PrivateResponse struct {
Title string
Tag string
}
実コード。
// Knocker is http client wrapper that Keep connection strings and Bearer token.
type Knocker struct {
Host string
Port int
Token string
}
// Knock send request with Bearer token and unmarshal response json.
func (k *Knocker) Knock(method string, path string, param io.Reader, v interface{}) (response *http.Response, body string, err error) {
url := fmt.Sprintf("http://%s:%d%s", k.Host, k.Port, path)
request, err := http.NewRequest(method, url, param)
if err != nil {
return nil, "", err
}
if k.Token != "" {
request.Header.Add("Authorization", "Bearer "+k.Token)
}
res, err := http.DefaultClient.Do(request)
if err != nil {
return nil, "", err
}
defer func() {
err := res.Body.Close()
if err != nil {
panic(err)
}
}()
resBody, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, "", err
}
if v != nil {
if err := json.Unmarshal(resBody, v); err != nil {
return nil, "", err
}
}
return res, string(resBody), nil
}
// Auth send request and keep response string in Token.
func (k *Knocker) Auth(method string, path string, param io.Reader) (response *http.Response, body string, err error) {
response, body, err = k.Knock(method, path, param, nil)
k.Token = body
return
}
あ。パラメータPOSTするテスト書き忘れた…明日で良いか。