post Image
ginのBindingとValidationについての調査メモ

GoのフレームワークginでのBindingとValidationの挙動を調査したので忘れないうちにアウトプットしとく。

環境

  • Mac:OS X Mavericks
  • Go:v1.4.2
  • gin:v1.0rc1

Binding&Validationのやり方

type TestForm struct {
    Name string `json:"name" binding:"required"`
    Text string `json:"text" binding:"required,max=1000"`
}

まず、Formを格納する構造体を定義してタグにBinding用の定義とValidation用の定義を書く。
Bindingタグの中に実施するValidationを列挙する。複数ある場合はカンマ区切りで書く。
※評価は左から順に行い、Errorがあった場合それ以降の評価は行わない
※利用できるValidationはここを参照

ちなみにここでは、

{"name": "taro", "text": "hogehoge"}

こういうJSON形式で受け取ることを想定している。
※Formで受けたい場合はjsonformに変えればよい。


r.POST("/test", func(c *gin.Context) {
    var form TestForm
    c.Bind(&form)

    log.Println(form.Name) // taro
    log.Println(form.Text) // hogehoge
    ...

次にHandlerFuncの中で定義したFormの構造体を宣言して、gin.ContextBindメソッドにポインタを与えると良しなにBindingしてくれる。

Validationエラーのハンドリング

このままだとValidationエラーになっていてもスルーしてFormには初期値が入った状態で処理が進んでしまうので、ハンドリング処理を書く。

r.POST("/test", func(c *gin.Context) {
    var form TestForm
    if err := c.Bind(&form); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"status": "BadRequest"})
        return
    }

    // 以下、正常処理

c.Bindは戻り値にerrorを返すので、それを拾ってあげれば良い。

errorの詳細を確認

Validationエラーの詳細をログに出したりResponseに含めたい場合もあると思うので、そのやり方。

単純なロギング

r.POST("/test", func(c *gin.Context) {
    var form TestForm
    if err := c.Bind(&form); err != nil {
        log.Println(err)
        c.JSON(http.StatusBadRequest, gin.H{"status": "BadRequest"})
        return
    }

    // 以下、正常処理

c.Bindの戻り値errをそのままログに出してみると、

Struct: TestForm
Field validation for "Name" failed on the "required" tag
Field validation for "Text" failed on the "required" tag

こんな感じのログが出力された。
ただロギングしたいだけならこれで十分かも知れない。

errorの詳細

次にerrの中身を確認してみる。

r.POST("/test", func(c *gin.Context) {
    var form TestForm
    if err := c.Bind(&form); err != nil {
        errors := err.(*validator.StructErrors)
        log.Println("Struct:", errors.Struct)
        for k, v := range errors.Errors {
            log.Println("Key:", k)
            log.Println("Field:", v.Field)
            log.Println("Param:", v.Param)
            log.Println("Tag:", v.Tag)
            log.Println("Kind", v.Kind)
            log.Println("Type:", v.Type)
            log.Println("Value", v.Value)
            log.Println("==========")
        }
        log.Println(errors.StructErrors)
        c.JSON(http.StatusBadRequest, gin.H{"status": "BadRequest"})
        return
    }

    // 以下、正常処理

ginのValidationは内部ではgopkg.in/bluesuncorp/validator(gin:v1.0rc1ではv5)を使っており、c.Bindの戻り値も同パッケージのStructErrors構造体を返している。

StructErrors
type StructErrors struct {
    Struct string
    Errors map[string]*FieldError
    StructErrors map[string]*StructErrors
}
FieldError
type FieldError struct {
    Field string
    Tag   string
    Kind  reflect.Kind
    Type  reflect.Type
    Param string
    Value interface{}
}

StructErrors構造体とFieldErrorはこのような構成になっている。

とりあえずStructErrorsの中身をひと通りログに出してみると、

Struct: TestForm
key: Name
Field: Name
Param: 
Tag: required
Kind string
Type: string
Value 
==========
key: Text
Field: Text
Param: 10
Tag: max
Kind string
Type: string
Value hogehogehoge
==========
StructErrors: map[]

こんな感じ。

要約すると以下のような内容。

要素 内容
StructErrors.Struct Validation対象の構造体名
StructErrors.Errors ErrorになったFieldを保持したMap(Key:Field名、Value:FieldError)
StructErrors.StructErrors Formが構造体の入れ子になっている場合、入れ子の構造体に対するValidationの結果が格納されるMap(Key:構造体名、Value:StructErrors)
FieldError.Field ErrorになったField名
FieldError.Tag Errorになったタグ名
FieldError.Kind ErrorになったFieldのKind
FieldError.Type ErrorになったFieldのType
FieldError.Param ErrorになったFieldのValidationに定義した値
FieldError.Value ErrorになったFieldに与えられた値

入れ子になったForm構造体のValidation

Formの構造体が入れ子になっていてもValidationを適用できる。

type BaseForm struct {
    ID int64 `json:"id" binding:"required"`
}

type TestForm struct {
    Name string   `json:"name" binding:"required"`
    Text string   `json:"text" binding:"required,max=1000"`
    Base BaseForm `json:"base"`
}

このようにFormの構造体を作り、

{
  "name": "hoge",
  "text": "hogehoge",
  "base": {
    "id": 123456
  }
}

こんな形式でリクエストしてやればOK。
これでBaseFormのidもValidationも実施してくれる。

とりあえずここまで

gopkg.in/bluesuncorp/validatorはValidationの種類も充実していて良さ気。必要なら独自Validationも実装できるみたいなので、次回はその辺も調べてみたいと思う。


『 Go 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。