Validator 検証ライブラリ
ドキュメント:validator/README.md at master · go-playground/validator (github.com)
公式サンプル:validator/_examples at master · go-playground/validator (github.com)
概要
go-playground/validator は構造体タグベースの値検証機能を実装しており、以下の独自機能があります:
交差フィールドおよび交差構造体検証のために検証タグとカスタム検証機能を使用可能
スライス、配列、マップ、または任意の多次元フィールドを検証可能
マップキーと値の検証にダイブ可能
基本型によって検証前にどのように処理するかを決定
カスタムフィールド型を処理可能
別名タグをサポート。複数の検証を 1 つのタグにマップでき、構造体検証定義をより簡単に
カスタムフィールド名(エラーメッセージに表示するための JSON 名など)を抽出可能
カスタム多言語エラーメッセージ
ginフレームワーク向けの標準デフォルト検証コンポーネント
インストール
go get github.com/go-playground/validator/v10インポート
import "github.com/go-playground/validator/v10"タグ
検証機能には多くの基本検証タグがあります。すべてのタグに対応する検証関数は baked_in.go ファイルで見つかります。検証機能の構造体タグは validate です。
例えば
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_addr | Unix ドメインソケットエンドポイントアドレス |
uri | 統一リソース識別子 |
url | 統一リソースロケータ |
url_encoded | 統一リソース識別子エンコーディング |
urn_rfc2141 | RFC 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 | 現在のフィールドの値が大文字列であることを検証 |
フォーマット
| タグ | 説明 |
|---|---|
base64 | Base64 文字列 |
base64url | Base64URL 文字列 |
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_alpha2 | iso 3166 alpha 2 の国コードの値によって検証 |
postcode_iso3166_alpha2_field | iso 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 | 指定されたフィールドがすべて存在しない場合、フィールドが存在しないか空である |
unique | 各 arr、map、slice 値が一意であることを検証 |
別名
| タグ | 説明 |
|---|---|
iscolor | hexcolor|rgb|rgba|hsl|hsla |
country_code | iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric |
演算子
| タグ | 説明 | 16 進 |
|---|---|---|
, | AND 演算子、複数の検証タグを使用、すべての条件を満たす必要がある、カンマ間にスペースなし | 0x2c |
| | OR 演算子、複数の検証タグを使用、ただし 1 つのみを満たす必要がある | 0x7c |
- | このフィールドの検証をスキップ | 0x2d |
= | パラメータマッチング記号 | 0x3d |
TIP
フィールド検証中に演算子をマッチングする場合、utf8 16 進表現に置き換える必要があります。例えば
filed string `validate:"contains=0x2c"`使用方法
以下では、コード例を使用して Validator の基本的な使用方法をいくつか紹介します。
シングルトン
var validate *validator.Validate使用時、公式はプログラム全体で 1 つの検証機能インスタンスのみを持つことを推奨しています。これにより一部のデータがキャッシュされます。
検証機能の作成
他のフレームワークと統合せずに Validator を単独で使用する場合、手動で検証機能を作成する必要があります。
validate = validator.New()構造体検証
func (v *Validate) Struct(s interface{}) errorStruct メソッドは構造体のすべてのパブリックフィールドを検証するために使用されます。デフォルトでは、自動的にネストされた構造体検証を実行します。無効な値が渡されるか値が nil の場合、InvalidValidationError を返します。検証に失敗した場合、ValidationErrors を返します。
例
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マップ検証
func (v *Validate) ValidateMap(data map[string]interface{}, rules map[string]interface{}) map[string]interface{}map タグを通じてキーと値のペアを検証します。
例
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 タグを使用します。
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スライスの各ユーザーを構造体検証で検証
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
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
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' tagTIP
Var メソッドは構造体、変数、スライス、およびマップの型を検証できます。dive タグと組み合わせて合理使用してください。
フィールド検証
フィールド検証パラメータは基本型ではなく、構造体フィールド名です。構造体自身のフィールド名またはネストされた構造体フィールド名にできます。
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 パラメータとして指定されたフィールドまたは構造体が存在しない場合、直接検証失敗と判断されます。例えば:
type Password struct {
FirstPassword string `validate:"eqfield=SeconddPaswod"` // SeconddPaswod != SecondPassword
SecondPassword string
}このようなスペルミスは検出が難しく、検証時には検証失敗としてのみ表示されます。これには特別な注意が必要です。
高度な使い方
次に、いくつかの高度な使用テクニックとより多くのカスタム操作を説明します。
カスタム別名
場合によっては、フィールドに多くの検証タグがあります。別のフィールドでそれらを再利用したい場合、直接コピーアンドペーストするかもしれませんが、これは最良の解決策ではありません。より良いアプローチは、再利用性を向上させるために別名を登録することです。以下の例を参照してください:
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)
}出力
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 を提供します。例を見てみましょう:
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 です。出力は以下の通り:
<nil>
Key: 'Example.Name' Error:Field validation for 'Name' failed on the 'is666' tagTIP
登録されたタグがすでに存在する場合、既存のタグで上書きされます。つまり、デフォルトのタグ検証ロジックを「書き換える」ことができます。
カスタム型検証関数
型検証関数は特定の型、通常は基本型ではない型専用です。同様に、デフォルトの基本型検証を上書きすることもできます。以下の例を参照してください:
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
}出力
Key: 'Example.Address' Error:Field validation for 'Address' failed on the 'required' tag
<nil>TIP
1 つの関数に複数の型を登録するの
