Gin
#Go #WEBフレームワーク
#GinのContext
httprouterがベース
httprouterはgo製Webフレームワークに使われている。
型のめも
gin.H
type H map[string]interface{}
routerのグルーピング
https://github.com/gin-gonic/gin#grouping-routes
code:go
func main() {
router := gin.Default()
// Simple group: v1
v1 := router.Group("/v1")
{
v1.POST("/login", loginEndpoint)
v1.POST("/submit", submitEndpoint)
v1.POST("/read", readEndpoint)
}
}
ミドルウェア
r.GET("/benchmark", MyBenchLogger(), benchEndpoint)
個別にミドルウェアを設定できる。
ミドルウェアはUseした順番に実行される。
以下の用に順番い呼び出される。
ミドルウェア1
ctx.Next()
ミドルウェア2
ctx.Next()
ミドルウェア3
ミドルウェア2
ミドルウェア1
Validation
https://github.com/gin-gonic/gin#model-binding-and-validation
validateとbindingのタグ名が異なるだけだと思う
code:validation
# go-playground/validatorではvalidate
validate:"required"
# ginではbindingを指定する
binding:"required"`
go-playground/validatorを使用しているみたい
https://github.com/go-playground/validator/blob/master/_examples/simple/main.go
https://github.com/go-playground/validator/blob/master/_examples/struct-level/main.go
structや[]もvalidateできるようだ。
GitHub - go-playground/validator: :100:Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving
リファレンス
c.ShouldBindQuery
GET qurery parameterのbind
Dive
https://godoc.org/github.com/go-playground/validator#hdr-Dive
Bindのとき
[]で深くネストしているときに使用するのか。
Bind実装
code:go
func (c *Context) Bind(obj interface{}) error {
b := binding.Default(c.Request.Method, c.ContentType())
return c.MustBindWith(obj, b)
}
Shoud
400 statusコードを設定しない
独自エラーハンドリングする場合。
Bindは、MustBindWithが呼び出される400でエラーハンドリングされている。
bindの場合の内部実装
https://github.com/gin-gonic/gin/blob/1a2bc0e7cb1a69b7750bd652d92c4d2b41504f04/context.go#L653
c.AbortWithError(http.StatusBadRequest, err) が呼び出されている
Like c.Bind() but this method does not set the response status code to 400 and abort if the json is not valid.
Formのbind
Multipart/Urlencoded binding
https://pkg.go.dev/github.com/gin-gonic/gin#section-readme
Ginのテスト
https://github.com/gin-gonic/gin#testing
code:go
package main
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestPingRoute(t *testing.T) {
router := setupRouter()
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/ping", nil)
router.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Equal(t, "pong", w.Body.String())
}
httptest
https://pkg.go.dev/net/http/httptest#ResponseRecorder
w := httptest.NewRecorder()
ResponseRecoderを生成
http.ResponseWriterインターフェイスを満たしている、
WriteでBodyにbufを書き込み
ServeHTTP実装
https://github.com/gin-gonic/gin/blob/v1.7.4/gin.go#L439
Request
https://pkg.go.dev/net/http#Request
スケール
アプリケーションサーバーは不要
gin自体goroutineが入っている。
1リクエストが一つのgoroutineで実行される?
参考
traefik
https://github.com/traefik/traefik
dockerの負荷分散
https://www.casleyconsulting.co.jp/blog/engineer/240/
go web framework benchmark
https://github.com/smallnest/go-web-framework-benchmark
jobrunner
https://github.com/bamzi/jobrunner
他、Go製のHTTPフレームワーク
echo
echoの場合、目的に応じてミドルウェアを導入
https://echo.labstack.com/cookbook/crud
#echo_(golang)
CRUD