🍋

gin(go)のBindまとめ

2022/07/06に公開

概要

ginのbind方法が少し複雑で、かつ毎回混乱する、毎回調べてしまうため、まとめ

BindJSON(MustBindWith) vs ShouldBindJSON(ShouldBindWith)

違いは次の通り

BindJSON

エラーが発生した場合、400エラーかつリクエストを中断する

ShoudBindJSON

400エラーにはならない、自分でエラーハンドリングする場合

Validation

ginで入力のバリデーションをする場合は、 構造体のキー名は binding を使う

example.go
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 を使う必要がある。

bad.go
// 1回目の呼び出しの場合、エラーは発生しない
if err := c.ShouldBind(&objA); err != nil {
 ...
}
// 2回目の呼び出しの場合、常にEOFのエラーが発生する
if err := c.ShouldBind(&objB); err != nil {
  ...
}
good.go
// 1回目の呼び出しの場合、コンテキストに値を読み込む
if err := c.ShouldBindBodyWith(&objA); err != nil {
 ...
}
// 2回目の呼び出しの場合、コンテキストから値を呼び出すためエラーは発生しない
if err := c.ShouldBindBodyWith(&objB); err != nil {
  ...
}

ただし、コンテキストに Body を読み込むため、パフォーマンスに僅かな影響があるため、通常1回だけ呼び出す場合は、このメソッドを使用してはならない。

このメソッドは JSON, XML, MsgPack, ProtoBuf の場合に必要で、Query, Form, FormPostc.ShouldBind() を利用して複数回呼び出すことが可能。

詳しくは
gin@v1.8.1#readme-try-to-bind-body-into-different-structs

Discussion