Skip to content

Validator 検証ライブラリ

公式サイト:go-playground/validator: 💯Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving (github.com)

ドキュメント:validator/README.md at master · go-playground/validator (github.com)

公式サンプル:validator/_examples at master · go-playground/validator (github.com)

ベンチマーク:go-playground/validator: 💯Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving (github.com)

概要

go-playground/validator は構造体タグベースの値検証機能を実装しており、以下の独自機能があります:

  • 交差フィールドおよび交差構造体検証のために検証タグとカスタム検証機能を使用可能

  • スライス、配列、マップ、または任意の多次元フィールドを検証可能

  • マップキーと値の検証にダイブ可能

  • 基本型によって検証前にどのように処理するかを決定

  • カスタムフィールド型を処理可能

  • 別名タグをサポート。複数の検証を 1 つのタグにマップでき、構造体検証定義をより簡単に

  • カスタムフィールド名(エラーメッセージに表示するための JSON 名など)を抽出可能

  • カスタム多言語エラーメッセージ

  • gin フレームワーク向けの標準デフォルト検証コンポーネント

インストール

powershell
go get github.com/go-playground/validator/v10

インポート

go
import "github.com/go-playground/validator/v10"

タグ

検証機能には多くの基本検証タグがあります。すべてのタグに対応する検証関数は baked_in.go ファイルで見つかります。検証機能の構造体タグは validate です。

例えば

go
type User {
  age int `validate:"gte=18"` // 18 歳以上を意味する
}

setTagName メソッドを通じてデフォルトタグを変更することもできます。

フィールド

タグ説明
eqcsfield別の構造体で、現在のフィールドの値がパラメータ値で指定されたフィールドと等しいことを検証
eqfield現在のフィールドの値がパラメータ値で指定されたフィールドと等しいことを検証
fieldcontains現在のフィールドの値がパラメータ値で指定されたフィールドを含むことを検証
fieldexcludes現在のフィールドの値がパラメータ値で指定されたフィールドを含まないことを検証
gtcsfield別の構造体で、現在のフィールドの値がパラメータ値で指定されたフィールドより大きいことを検証
gtecsfield別の構造体で、現在のフィールドの値がパラメータ値で指定されたフィールド以上であることを検証
gtefield現在のフィールドの値がパラメータ値で指定されたフィールド以上であることを検証
gtfield現在のフィールドの値がパラメータ値で指定されたフィールドより大きいことを検証
ltcsfield別の構造体で、現在のフィールドの値がパラメータ値で指定されたフィールドより小さいことを検証
ltecsfield別の構造体で、現在のフィールドの値がパラメータ値で指定されたフィールド以下であることを検証
ltefield現在のフィールドの値がパラメータ値で指定されたフィールド以下であることを検証
ltfield現在のフィールドの値がパラメータ値で指定されたフィールドより小さいことを検証
necsfield現在のフィールドの値がパラメータ値で指定された別の構造体のフィールドと等しくないことを検証
nefield現在のフィールドの値がパラメータ値で指定されたフィールドと等しくないことを検証

ネットワーク

タグ説明
cidrクラスレスインタードメインルーティング CIDR
cidrv4クラスレスインタードメインルーティング CIDRv4
cidrv6クラスレスインタードメインルーティング CIDRv6
datauriデータ統一リソース識別子
fqdn完全修飾ドメイン名 (FQDN)
hostnameホスト名 RFC 952
hostname_port主にソケットアドレスに使用される <dns>:<port> 組み合わせのフィールド検証
hostname_rfc1123ホスト名 RFC 952
ipインターネットプロトコルアドレス IP
ip4_addrインターネットプロトコルアドレス IPv4
ip6_addrインターネットプロトコルアドレス IPv6
ip_addrインターネットプロトコルアドレス IP
ipv4インターネットプロトコルアドレス IPv4
ipv6インターネットプロトコルアドレス IPv6
macメディアアクセスコントロールアドレス、LAN アドレスとしても知られる
tcp4_addr伝送制御プロトコルアドレス TCP4
tcp6_addr伝送制御プロトコルアドレス TCPv6
tcp_addr伝送制御プロトコルアドレス TCP
udp4_addrユーザーデータグラムプロトコルアドレス UDPv4
udp6_addrユーザーデータグラムプロトコルアドレス UDPv6
udp_addrユーザーデータグラムプロトコルアドレス UDP
unix_addrUnix ドメインソケットエンドポイントアドレス
uri統一リソース識別子
url統一リソースロケータ
url_encoded統一リソース識別子エンコーディング
urn_rfc2141RFC 2141 統一リソース名

文字列

タグ説明
alpha現在のフィールドの値が有効なアルファベット文字列であることを検証
alphanum現在のフィールドの値が有効な英数字文字列であることを検証
alphanumunicode現在のフィールドの値が有効な英数字ユニコード文字列であることを検証
alphaunicode現在のフィールドの値が有効なアルファベットユニコード文字列であることを検証
asciiフィールドの値が有効な ASCII 文字であることを検証
boolean現在のフィールドの値が有効なブール値であるか、安全にブール値に変換可能であることを検証
containsフィールドの値がパラメータで指定されたテキストを含むことを検証
containsanyフィールドの値がパラメータで指定された任意の文字を含むことを検証
containsruneフィールドの値がパラメータで指定されたルーンを含むことを検証
endsnotwithフィールドの値がパラメータで指定されたテキストで終わらないことを検証
endswithフィールドの値がパラメータで指定されたテキストで終わることを検証
excludesフィールドの値がパラメータで指定されたテキストを含まないことを検証
excludesallフィールドの値がパラメータで指定された任意の文字を含まないことを検証
excludesruneフィールドの値がパラメータで指定されたルーンを含まないことを検証
lowercase現在のフィールドの値が小文字列であることを検証
multibyteフィールドの値がマルチバイト文字を持つことを検証
number現在のフィールドの値が有効な数値であることを検証
numeric現在のフィールドの値が有効な数値であることを検証
printasciiフィールドの値が有効な印刷可能 ASCII 文字であることを検証
startsnotwithフィールドの値がパラメータで指定されたテキストで始まらないことを検証
startswithフィールドの値がパラメータで指定されたテキストで始まることを検証
uppercase現在のフィールドの値が大文字列であることを検証

フォーマット

タグ説明
base64Base64 文字列
base64urlBase64URL 文字列
bic現在のフィールドの値が ISO 9362 で定義された有効な BIC コード(SWIFT コード)であることを検証
bcp47_language_tag現在のフィールドの値が BCP47 言語タグであることを検証
btc_addrフィールドの値が有効な BTC アドレスであることを検証
btc_addr_bech32フィールドの値が有効な bech32 BTC アドレスであることを検証
credit_card現在のフィールドの値が有効なクレジットカード番号であることを検証
datetime現在のフィールドの値が有効な日時文字列であることを検証
e164現在のフィールドの値が有効な e.164 形式電話番号であることを検証
email現在のフィールドの値が有効なメールアドレスであることを検証
eth_addrフィールドの値が有効なイーサリアムアドレスであることを検証
hexadecimal現在のフィールドの値が有効な 16 進数であることを検証
hexcolor現在のフィールドの値が有効な 16 進カラーであることを検証
hsl現在のフィールドの値が有効な HSL カラーであることを検証
hsla現在のフィールドの値が有効な HSLA カラーであることを検証
html現在のフィールドの値が有効な HTML であることを検証
html_encoded現在のフィールドの値が有効な HTML エンコードであることを検証
isbnフィールドの値が有効な v10 または v13 ISBN(国際標準図書番号)であることを検証
isbn10フィールドの値が有効な v10 ISBN であることを検証
isbn13フィールドの値が有効な v13 ISBN であることを検証
iso3166_1_alpha2現在のフィールドの値が有効な iso3166-1 alpha-2 国コードであることを検証
iso3166_1_alpha3現在のフィールドの値が有効な iso3166-1 alpha-3 国コードであることを検証
iso3166_1_alpha_numeric現在のフィールドの値が有効な iso3166-1 英数字国コードであることを検証
iso3166_2現在のフィールドの値が有効な国地域コード(ISO 3166-2)であることを検証
iso4217現在のフィールドの値が有効な通貨コード(ISO 4217)であることを検証
json現在のフィールドの値が有効な JSON 文字列であることを検証
jwt現在のフィールドの値が有効な JWT 文字列であることを検証
latitudeフィールドの値が有効な緯度座標であることを検証
longitudeフィールドの値が有効な経度座標であることを検証
postcode_iso3166_alpha2iso 3166 alpha 2 の国コードの値によって検証
postcode_iso3166_alpha2_fieldiso 3166 alpha 2 の国コード値を表すフィールドによって検証
rgb現在のフィールドの値が有効な RGB カラーであることを検証
rgba現在のフィールドの値が有効な RGBA カラーであることを検証
ssnフィールドの値が有効な SSN であることを検証
timezone現在のフィールドの値が有効なタイムゾーン文字列であることを検証
uuidフィールドの値が任意のバージョンの有効な UUID であることを検証
uuid3フィールドの値が有効な UUID v3 であることを検証
uuid3_rfc4122フィールドの値が有効な RFC4122 v3 UUID であることを検証
uuid4フィールドの値が有効な v4 UUID であることを検証
uuid4_rfc4122フィールドの値が有効な RFC4122 v4 UUID であることを検証
uuid5フィールドの値が有効な v5 UUID であることを検証
uuid5_rfc4122フィールドの値が有効な RFC4122 v5 UUID であることを検証
uuid_rfc4122フィールドの値が任意のバージョンの有効な RFC4122 UUID であることを検証
md4フィールドの値が有効な MD4 であることを検証
md5フィールドの値が有効な MD5 であることを検証
sha256フィールドの値が有効な SHA256 であることを検証
sha384フィールドの値が有効な SHA384 であることを検証
sha512フィールドの値が有効な SHA512 であることを検証
ripemd128フィールドの値が有効な RIPEMD128 であることを検証
ripemd160フィールドの値が有効な RIPEMD160 であることを検証
tiger128フィールドの値が有効な TIGER128 であることを検証
tiger160フィールドの値が有効な TIGER160 であることを検証
tiger192フィールドの値が有効な TIGER192 であることを検証
semver現在のフィールドの値がセマンティックバージョニング 2.0.0 で定義された有効な semver バージョンであることを検証
ulidフィールドの値が有効な ULID であることを検証

比較

タグ説明
eq等しい
gtより大きい
gte以上
ltより小さい
lte以下
ne等しくない

その他

タグ説明
dirファイルディレクトリ
fileファイルパス
isdefault現在のフィールドの値がデフォルトの静的値であることを検証
lenフィールド長
max最大値
min最小値
oneof列挙値の 1 つかどうか
omitemptyフィールドが設定されていない場合、フィールドを無視
required必須値
required_if他の指定されたフィールドが指定された値と等しい場合にのみ、フィールドが存在し空でない必要がある
required_unless他の指定されたフィールドが指定された値と等しくない限り、フィールドが存在し空でない必要がある
required_with指定されたフィールドのいずれかが存在する場合、フィールドが存在し空でない必要がある
required_with_all指定されたフィールドがすべて存在する場合、フィールドが存在し空でない必要がある
required_without指定されたフィールドのいずれかが存在しない場合、フィールドが存在し空でない必要がある
required_without_all指定されたフィールドがすべて存在しない場合、フィールドが存在し空でない必要がある
excluded_if他の指定されたフィールドが指定された値と等しい場合にのみ、フィールドが存在しないか空である
excluded_unless他の指定されたフィールドが指定された値と等しくない限り、フィールドが存在しないか空である
excluded_with指定されたフィールドのいずれかが存在する場合、フィールドが存在しないか空である
excluded_with_all指定されたフィールドがすべて存在する場合、フィールドが存在しないか空である
excluded_without指定されたフィールドのいずれかが存在しない場合、フィールドが存在しないか空である
excluded_without_all指定されたフィールドがすべて存在しない場合、フィールドが存在しないか空である
uniquearrmapslice 値が一意であることを検証

別名

タグ説明
iscolorhexcolor|rgb|rgba|hsl|hsla
country_codeiso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric

演算子

タグ説明16 進
,AND 演算子、複数の検証タグを使用、すべての条件を満たす必要がある、カンマ間にスペースなし0x2c
|OR 演算子、複数の検証タグを使用、ただし 1 つのみを満たす必要がある0x7c
-このフィールドの検証をスキップ0x2d
=パラメータマッチング記号0x3d

TIP

フィールド検証中に演算子をマッチングする場合、utf8 16 進表現に置き換える必要があります。例えば

go
filed string `validate:"contains=0x2c"`

使用方法

以下では、コード例を使用して Validator の基本的な使用方法をいくつか紹介します。

シングルトン

go
var validate *validator.Validate

使用時、公式はプログラム全体で 1 つの検証機能インスタンスのみを持つことを推奨しています。これにより一部のデータがキャッシュされます。

検証機能の作成

他のフレームワークと統合せずに Validator を単独で使用する場合、手動で検証機能を作成する必要があります。

go
validate = validator.New()

構造体検証

go
func (v *Validate) Struct(s interface{}) error

Struct メソッドは構造体のすべてのパブリックフィールドを検証するために使用されます。デフォルトでは、自動的にネストされた構造体検証を実行します。無効な値が渡されるか値が nil の場合、InvalidValidationError を返します。検証に失敗した場合、ValidationErrors を返します。

go
package validate

import (
  "fmt"
  "github.com/go-playground/validator/v10"
  "testing"
)

type User struct {
  Name    string `validate:"contains=jack"` // 名前に jack を含む
  Age     int    `validate:"gte=18"`        // 18 歳以上
  Address string `validate:"endswith=市"`    // 市で終わる
}

func TestStruct(t *testing.T) {
  validate := validator.New()
  user := User{
    Name:    "jacklove",
    Age:     17,
    Address: "滔博市",
  }
  err := validate.Struct(user)
  for _, err := range err.(validator.ValidationErrors) {
    fmt.Println(err.Namespace()) // ネームスペース
    fmt.Println(err.Field())
    fmt.Println(err.StructNamespace())
    fmt.Println(err.StructField())
    fmt.Println(err.Tag())
    fmt.Println(err.ActualTag())
    fmt.Println(err.Kind())
    fmt.Println(err.Type())
    fmt.Println(err.Value())
    fmt.Println(err.Param())
    fmt.Println()
  }
  fmt.Println(err)
}

出力

User.Age
Age
User.Age
Age
gte
gte
int
int
17
18

Key: 'User.Age' Error:Field validation for 'Age' failed on the 'gte' tag

マップ検証

go
func (v *Validate) ValidateMap(data map[string]interface{}, rules map[string]interface{}) map[string]interface{}

map タグを通じてキーと値のペアを検証します。

go
func TestMap(t *testing.T) {
   user := map[string]interface{}{
      "name":    "jak",
      "age":     17,
      "address": "滔博市",
   }
   rules := map[string]interface{}{
      "name":    "contains=jacklove",
      "age":     "gte=18",
      "address": "endswith=市",
   }

   validate := validator.New()

   validateMap := validate.ValidateMap(user, rules)
   fmt.Println(validateMap)
}

出力

map[age:Key: '' Error:Field validation for '' failed on the 'gte' tag name:Key: '' Error:Field validation for '' failed on the 'contains' tag]

スライス検証

文字列スライスを検証します。dive 前のタグはスライスを検証し、dive 後のタグはスライスの値を検証します。ネストされたスライスも同じ原則に従います - 次元数と同じ数の dive タグを使用します。

go
func TestSlice1(t *testing.T) {
  list := []string{"jack", "mike", "lisa", "golang"}
  err := validator.New().Var(list, "max=5,dive,contains=a,min=5") // スライス最大長 5、要素は文字 'a' を含む、最小長 5
  fmt.Println(err)
}

出力

Key: '[0]' Error:Field validation for '[0]' failed on the 'min' tag
Key: '[1]' Error:Field validation for '[1]' failed on the 'contains' tag
Key: '[2]' Error:Field validation for '[2]' failed on the 'min' tag

スライスの各ユーザーを構造体検証で検証

go
func TestSlice(t *testing.T) {
   userList := make([]User, 0)
   user := User{
      Name:    "jacklove",
      Age:     17,
      Address: "滔博市",
   }
   userList = append(userList, user)
   err := validator.New().Var(userList, "dive") // "dive" は深い検証を意味し、要素が構造体の場合自動的に構造体検証を実行
   fmt.Println(err)
}

出力

Key: '[0].Age' Error:Field validation for 'Age' failed on the 'gte' tag

変数検証

シンプルで理解しやすく、過度な説明は不要です

例 1

go
func TestVar(t *testing.T) {
   name := "jack"
   err := validator.New().Var(name, "max=5,contains=a,min=1,endswith=l") // 最大長 5、最小長 1、文字 'a' を含む、文字 'l' で終わる
   fmt.Println(err)
}

出力

Key: '' Error:Field validation for '' failed on the 'endswith' tag

例 2

go
func TestVar1(t *testing.T) {
   age := 18
   err := validator.New().Var(age, "gte=19")
   fmt.Println(err)
}

出力

Key: '' Error:Field validation for '' failed on the 'gte' tag

TIP

Var メソッドは構造体、変数、スライス、およびマップの型を検証できます。dive タグと組み合わせて合理使用してください。

フィールド検証

フィールド検証パラメータは基本型ではなく、構造体フィールド名です。構造体自身のフィールド名またはネストされた構造体フィールド名にできます。

go
type Password struct {
   FirstPassword  string `validate:"eqfield=SecondPassword"` // 2 つのパスワード入力が等しいことを検証
   SecondPassword string
}

type RegisterUser struct {
   Username string `validate:"necsfield=Password.FirstPassword"` // セキュリティのため登録時にパスワードがユーザー名と一致することを禁止
   Password Password
}

func TestCrossStructFieldValidate(t *testing.T) {
   validate = validator.New()
   // 失敗
   fmt.Println(validate.Struct(RegisterUser{
      Username: "gopher",
      Password: Password{
         FirstPassword:  "gopher",
         SecondPassword: "gophers",
      },
   }))
   // 成功
   fmt.Println(validate.Struct(RegisterUser{
      Username: "gophers",
      Password: Password{
         FirstPassword:  "gopher",
         SecondPassword: "gopher",
      },
   }))
}

出力

Key: 'RegisterUser.Username' Error:Field validation for 'Username' failed on the 'necsfield' tag
Key: 'RegisterUser.Password.FirstPassword' Error:Field validation for 'FirstPassword' failed on the 'eqfield' tag
<nil>

WARNING

フィールド検証を使用する際、Tag パラメータとして指定されたフィールドまたは構造体が存在しない場合、直接検証失敗と判断されます。例えば:

go
type Password struct {
   FirstPassword  string `validate:"eqfield=SeconddPaswod"` // SeconddPaswod != SecondPassword
   SecondPassword string
}

このようなスペルミスは検出が難しく、検証時には検証失敗としてのみ表示されます。これには特別な注意が必要です。

高度な使い方

次に、いくつかの高度な使用テクニックとより多くのカスタム操作を説明します。

カスタム別名

場合によっては、フィールドに多くの検証タグがあります。別のフィールドでそれらを再利用したい場合、直接コピーアンドペーストするかもしれませんが、これは最良の解決策ではありません。より良いアプローチは、再利用性を向上させるために別名を登録することです。以下の例を参照してください:

go
var validate *validator.Validate

const PERSON_NAME_RULES = "max=10,min=1,contains=jack"

func TestAlias(t *testing.T) {
  validate = validator.New()
    // 別名を登録
  validate.RegisterAlias("namerules", PERSON_NAME_RULES)
  type person struct {
    FirstName string `validate:"namerules"` // 別名を使用
    LastName  string `validate:"namerules"`
  }

  err := validate.Struct(person{
    FirstName: "",
    LastName:  "",
  })

  fmt.Println(err)
}

出力

go
Key: 'person.FirstName' Error:Field validation for 'FirstName' failed on the 'namerules' tag
Key: 'person.LastName' Error:Field validation for 'LastName' failed on the 'namerules' tag

カスタム検証関数

コンポーネントの組み込み検証タグは基本シナリオには十分ですが、特殊な要件のために独自のロジックを定義する必要がある場合があります。Validator は検証関数をカスタマイズするための関連 API を提供します。例を見てみましょう:

go
func TestCustomValidate(t *testing.T) {
   validate = validator.New()
   fmt.Println(validate.RegisterValidation("is666", is666))
   type Example struct {
      Name string `validate:"is666"`
   }
   fmt.Println(validate.Struct(Example{Name: "777"}))
   fmt.Println(validate.Struct(Example{Name: "666"}))
}

func is666(fl validator.FieldLevel) bool {
   return fl.Field().String() == "666"
}

フィールド値が "666" に等しいかを確認する関数を作成し、対応するタグは is666 です。出力は以下の通り:

go
<nil>
Key: 'Example.Name' Error:Field validation for 'Name' failed on the 'is666' tag

TIP

登録されたタグがすでに存在する場合、既存のタグで上書きされます。つまり、デフォルトのタグ検証ロジックを「書き換える」ことができます。

カスタム型検証関数

型検証関数は特定の型、通常は基本型ではない型専用です。同様に、デフォルトの基本型検証を上書きすることもできます。以下の例を参照してください:

go
type Address struct {
  name string
}

func TestCustomTypeValidate(t *testing.T) {
  validate = validator.New()
  validate.RegisterCustomTypeFunc(ValidateAddress, Address{}) // 型検証関数と対応する型を登録
  type Example struct {
    Address Address `validate:"required"`
  }
  fmt.Println(validate.Struct(Example{Address: Address{name: ""}}))
  fmt.Println(validate.Struct(Example{Address: Address{name: "cn"}}))
}

func ValidateAddress(value reflect.Value) interface{} {
  if address, ok := value.Interface().(Address); ok {
    // エラー処理
    if address.name == "" {
      return address.name
    }

    return value // フィールドを返すことは検証合格を意味する
  }
  return nil
}

出力

go
Key: 'Example.Address' Error:Field validation for 'Address' failed on the 'required' tag
<nil>

TIP

1 つの関数に複数の型を登録するの

Golang学习网由www.golangdev.cn整理维护