ビジネスルール
タグ層は単一フィールドの形を扱います;Validate() メソッドはそれ 以外を全部扱います。本ページは本番コードでよく見るパターンを集めた ものです。
クロスフィールドの相等
go
type Form struct {
Password string `valid:"required;minlen:8" label:"密码"`
RepeatPassword string `valid:"required;equal:Password" label:"重复密码"`
}あるいは等価に Validate で:
go
func (f *Form) Validate() error {
if f.Password != f.RepeatPassword {
return errors.New("两次输入的密码不一致")
}
return nil
}条件付き必須
go
type Address struct {
Country string `valid:"required;list:CN,US,JP"`
State string
Province string
}
func (a Address) Validate() error {
switch a.Country {
case "US":
if a.State == "" {
return errors.New("US 地址必须填写 state")
}
case "CN":
if a.Province == "" {
return errors.New("中国地址必须填写省份")
}
}
return nil
}日時の境界
govalid は日付チェッカーを同梱しません。カスタムでラップします:
go
import "time"
govalid.SetMessageTemplates(map[string]string{
"afterToday": "必须晚于今天",
})
govalid.Checkers["afterToday"] = func(c govalid.CheckerContext) *govalid.ErrContext {
t, ok := c.FieldValue.(time.Time)
if !ok {
return govalid.MakeValueTypeError(c)
}
if !t.After(time.Now()) {
return govalid.NewErrorContext(c)
}
return nil
}
type Booking struct {
StartAt time.Time `valid:"required;afterToday" label:"开始时间"`
}データベースに対するユニーク性
Validate() はただの Go コード——リポジトリを呼んでください:
go
func (u *CreateUser) Validate() error {
if exists, _ := userRepo.UsernameExists(u.Username); exists {
return fmt.Errorf("用户名 %q 已被占用", u.Username)
}
return nil
}WARNING
バリデーションは認可ではありません。セキュリティ関連のチェックを データベースに依存するなら、書き込みを行うトランザクション内で そのチェックを行ってください——Validate() は UX 上の親切心であり、 保証ではありません。
エラーを豊かにする
1 つの構造体が多種のドメイン特有の理由で失敗しうる場合、Validate() から型付きセンチネルを返し、後で switch します:
go
var (
errAdminBlocked = errors.New("admin reserved")
errEmailReused = errors.New("email already in use")
)
func (u *CreateUser) Validate() error {
if u.Username == "admin" {
return errAdminBlocked
}
if reused, _ := userRepo.EmailExists(u.Email); reused {
return errEmailReused
}
return nil
}
errs, _ := govalid.Check(form)
for _, e := range errs {
switch {
case strings.Contains(e.Error(), errAdminBlocked.Error()):
// ...
}
}govalid はあなたが返したエラーを文字列化するので、トークンベースの 識別が今のところ最もシンプルなパスです。将来のバージョンで Unwrap が直接公開されるかもしれません。