Go言語で構造体をValidation
validatorを使って、Go言語の構造体をスマートにValidationしてみました。
Table of Contents
はじめに
Go言語で開発しているとstructのフィールドを検証したくなることはないでしょうか。
例えば、ユーザからの入力を受け取るインタフェース部分などです。
functionやreceiverを使えば目的を達成することはできます。
しかし、都度if文や定義が必要になり泥臭く感じることはないでしょうか。
本記事ではvalidatorというライブラリを使ってそれをスマートに解決します。
標準のやり方
以下のような構造体とルールがあるとします。
フィールド名 | 型 | 有効値 |
---|---|---|
ID | 数値 | 1~99 |
Name | 文字列 | 9文字以内 |
ライブラリを使わずに実装すると、以下の様な実装になると思います。
package main
import (
"fmt"
"log"
)
type Fruit struct {
ID int
Name string
}
func (r *Fruit) validate() error {
if !(0 < r.ID && r.ID <= 99) {
return errors.New("FruitのIDは1~99でなければいけません.")
}
if len(r.Name) >= 10 {
return errors.New("FruitのNameは10文字未満でなければいけません.")
}
return nil
}
func main() {
orange := Fruit{
ID: 100,
Name: "orange-range",
}
if err := orange.validate(); err != nil {
log.Fatal(err)
}
fmt.Printf("%v\n", orange)
}
この実行結果は以下のようになります。
2018/10/15 01:19:47 FruitのIDは1~99でなければいけません.
validatorを使った場合
validatorを使うとstructフィールドのタグに条件を記載するだけでOKです。
先ほどのコードは以下のように書くことができます。
package main
import (
"fmt"
"log"
"gopkg.in/go-playground/validator.v9"
)
type Fruit struct {
ID int `validate:"min=1,max=99"`
Name string `validate:"max=9"`
}
func main() {
validate := validator.New()
orange := Fruit{
ID: 100,
Name: "orange-range",
}
if err := validate.Struct(orange); err != nil {
log.Fatal(err)
}
fmt.Printf("%v\n", orange)
}
この実行結果は以下のようになります。
2018/10/15 01:35:38 Key: 'Fruit.ID' Error:Field validation for 'ID' failed on the 'max' tag
Key: 'Fruit.Name' Error:Field validation for 'Name' failed on the 'max' tag
今回の例では2つの条件共に違反しているため、2つの検証エラーが出ます。
maxやminの値を具体的に教えてくれないためエラーメッセージとしては不親切ですね..。
自由にメッセージをカスタマイズする方法があれば知りたいです。
使えるタグ一覧
公式ドキュメントを参照して下さい。
一番使うことが多いのはrequired
ですね。
トラブルシューティング
以下はよくハマッたケースです。
invalid memory address or nil pointer dereference
Validateインスタンスの初期化がされていません。
validate := validator.New()
のように初期化していることを確認してください。
タグに記載したルールでvalidationできない
実行エラーや検証エラーにならないケースです。
以下を確認してください。
- フィールド名の先頭が大文字になっていること
- タグに記載された
:
の後にスペースが無いこと
例えば以下の例はどちらName
がNGです。
type Fruit struct {
name string `validate:"max=9"`
}
type Fruit struct {
Name string `validate: "max=9"`
}
総括
validatorを使って、Go言語の構造体をスマートにValidationしてみました。
今はエラーメッセージをカスタマイズしたり、エラーの種類によって処理を変える方法が分かっていません。
今後、可能になった(やり方が分かった)場合は追記したいと思います。