gin(go)のBindまとめ
概要
ginのbind方法が少し複雑で、かつ毎回混乱する、毎回調べてしまうため、まとめ
BindJSON(MustBindWith) vs ShouldBindJSON(ShouldBindWith)
違いは次の通り
BindJSON
エラーが発生した場合、400エラーかつリクエストを中断する
ShoudBindJSON
400エラーにはならない、自分でエラーハンドリングする場合
Validation
ginで入力のバリデーションをする場合は、 構造体のキー名は binding
を使う
var b struct {
Name string `json:"name" binding:"required"`
}
if err := c.ShouldBindJSON(&b); err != nil {
c.AbortWithStatus(http.StatusBadRequest)
return
}
内部では go-playground の validator/v10 を使っている。
gin@v1.8.1#readme-model-binding-and-validation
間違えポイントは validator/v10 では構造体のキー名が validate
なのに対し、ginでは binding
を使う必要がある
(キー名を validate
とすると、ginではバリデーションされないため注意が必要)
Custom validator
カスタムのバリデーションが作成できる。基本的な使い方は validator/v10 と同じ。
詳しくは次のリンクを参照。
gin@v1.8.1#readme-custom-validators
複数回Bindを呼び出す場合
ShoudBind
を使うと通常 Body
を消費して、複数回呼び出すことができない。
複数回呼び出す場合は、 ShouldBindBodyWith
を使う必要がある。
// 1回目の呼び出しの場合、エラーは発生しない
if err := c.ShouldBind(&objA); err != nil {
...
}
// 2回目の呼び出しの場合、常にEOFのエラーが発生する
if err := c.ShouldBind(&objB); err != nil {
...
}
// 1回目の呼び出しの場合、コンテキストに値を読み込む
if err := c.ShouldBindBodyWith(&objA); err != nil {
...
}
// 2回目の呼び出しの場合、コンテキストから値を呼び出すためエラーは発生しない
if err := c.ShouldBindBodyWith(&objB); err != nil {
...
}
ただし、コンテキストに Body
を読み込むため、パフォーマンスに僅かな影響があるため、通常1回だけ呼び出す場合は、このメソッドを使用してはならない。
このメソッドは JSON
, XML
, MsgPack
, ProtoBuf
の場合に必要で、Query
, Form
, FormPost
は c.ShouldBind()
を利用して複数回呼び出すことが可能。
詳しくは
gin@v1.8.1#readme-try-to-bind-body-into-different-structs
Discussion