|
1 | | -// Package validator implements value validations |
2 | | -// |
3 | | -// The MIT License (MIT) |
4 | | -// |
5 | | -// Copyright (c) 2015 Dean Karn |
6 | | -// |
7 | | -// Permission is hereby granted, free of charge, to any person obtaining a copy |
8 | | -// of this software and associated documentation files (the "Software"), to deal |
9 | | -// in the Software without restriction, including without limitation the rights |
10 | | -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
11 | | -// copies of the Software, and to permit persons to whom the Software is |
12 | | -// furnished to do so, subject to the following conditions: |
13 | | -// |
14 | | -// The above copyright notice and this permission notice shall be included in all |
15 | | -// copies or substantial portions of the Software. |
16 | | -// |
17 | | -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18 | | -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19 | | -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
20 | | -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
21 | | -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
22 | | -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
23 | | -// SOFTWARE. |
| 1 | +/* |
| 2 | +Package validator implements value validations for structs and individual fields based on tags. |
| 3 | +
|
| 4 | +Built In Validator |
| 5 | +
|
| 6 | +The package contains a built in Validator instance for use, |
| 7 | +but you may also create a new instance if needed. |
| 8 | +
|
| 9 | + // built in |
| 10 | + errs := validator.ValidateStruct(//your struct) |
| 11 | + errs := validator.ValidateFieldByTag(field, "omitempty,min=1,max=10") |
| 12 | +
|
| 13 | + // new |
| 14 | + newValidator = validator.New("struct tag name", validator.BakedInFunctions) |
| 15 | +
|
| 16 | +A simple example usage: |
| 17 | +
|
| 18 | + type UserDetail { |
| 19 | + Details string `validate:"-"` |
| 20 | + } |
| 21 | +
|
| 22 | + type User struct { |
| 23 | + Name string `validate:"required,max=60"` |
| 24 | + PreferedName string `validate:"omitempty,max=60"` |
| 25 | + Sub UserDetail |
| 26 | + } |
| 27 | +
|
| 28 | + user := &User { |
| 29 | + Name: "", |
| 30 | + } |
| 31 | +
|
| 32 | + // errs will contain a hierarchical list of errors |
| 33 | + // using the StructValidationErrors struct |
| 34 | + // or nil if no errors exist |
| 35 | + errs := validator.ValidateStruct(user) |
| 36 | +
|
| 37 | + // in this case 1 error Name is required |
| 38 | + errs.Struct will be "User" |
| 39 | + errs.StructErrors will be empty <-- fields that were structs |
| 40 | + errs.Errors will have 1 error of type FieldValidationError |
| 41 | +
|
| 42 | +Error Handling |
| 43 | +
|
| 44 | +The error can be used like so |
| 45 | +
|
| 46 | + fieldErr, _ := errs["Name"] |
| 47 | + fieldErr.Field // "Name" |
| 48 | + fieldErr.ErrorTag // "required" |
| 49 | +
|
| 50 | +Both StructValidationErrors and FieldValidationError implement the Error interface but it's |
| 51 | +intended use is for development + debugging, not a production error message. |
| 52 | +
|
| 53 | + fieldErr.Error() // Field validation for "Name" failed on the "required" tag |
| 54 | + errs.Error() |
| 55 | + // Struct: User |
| 56 | + // Field validation for "Name" failed on the "required" tag |
| 57 | +
|
| 58 | +Why not a better error message? because this library intends for you to handle your own error messages |
| 59 | +
|
| 60 | +Why should I handle my own errors? Many reasons, for me building and internationalized application |
| 61 | +I needed to know the field and what validation failed so that I could provide an error in the users specific language. |
| 62 | +
|
| 63 | + if fieldErr.Field == "Name" { |
| 64 | + switch fieldErr.ErrorTag |
| 65 | + case "required": |
| 66 | + return "Translated string based on field + error" |
| 67 | + default: |
| 68 | + return "Translated string based on field" |
| 69 | + } |
| 70 | +
|
| 71 | +The hierarchical structure is hard to work with sometimes.. Agreed Flatten function to the rescue! |
| 72 | +Flatten will return a map of FieldValidationError's but the field name will be namespaced. |
| 73 | +
|
| 74 | + // if UserDetail Details field failed validation |
| 75 | + Field will be "Sub.Details" |
| 76 | +
|
| 77 | + // for Name |
| 78 | + Field will be "Name" |
| 79 | +
|
| 80 | +Custom Functions |
| 81 | +
|
| 82 | +Custom functions can be added |
| 83 | +
|
| 84 | + //Structure |
| 85 | + func customFunc(field interface{}, param string) bool { |
| 86 | +
|
| 87 | + if whatever { |
| 88 | + return false |
| 89 | + } |
| 90 | +
|
| 91 | + return true |
| 92 | + } |
| 93 | +
|
| 94 | + validator.AddFunction("custom tag name", customFunc) |
| 95 | + // NOTE: using the same tag name as an existing function |
| 96 | + // will overwrite the existing one |
| 97 | +
|
| 98 | +Custom Tag Name |
| 99 | +
|
| 100 | +A custom tag name can be set to avoid conficts, or just have a shorter name |
| 101 | +
|
| 102 | + validator.SetTag("valid") |
| 103 | +
|
| 104 | +Multiple Validators |
| 105 | +
|
| 106 | +Multiple validators on a field will process in the order defined |
| 107 | +
|
| 108 | + type Test struct { |
| 109 | + Field `validate:"max=10,min=1"` |
| 110 | + } |
| 111 | +
|
| 112 | + // max will be checked then min |
| 113 | +
|
| 114 | +Bad Validator definitions are not handled by the library |
| 115 | +
|
| 116 | + type Test struct { |
| 117 | + Field `validate:"min=10,max=0"` |
| 118 | + } |
| 119 | +
|
| 120 | + // this definition of min max will never validate |
| 121 | +
|
| 122 | +Baked In Validators |
| 123 | +
|
| 124 | +Here is a list of the current built in validators: |
| 125 | +
|
| 126 | + - |
| 127 | + Tells the validation to skip this struct field; this is particularily |
| 128 | + handy in ignoring embedded structs from being validated. (Usage: -) |
| 129 | +
|
| 130 | + omitempty |
| 131 | + Allows conitional validation, for example if a field is not set with |
| 132 | + a value (Determined by the required validator) then other validation |
| 133 | + such as min or max won't run, but if a value is set validation will run. |
| 134 | + (Usage: omitempty) |
| 135 | + len |
| 136 | + For numbers, max will ensure that the value is |
| 137 | + equal to the parameter given. For strings, it checks that |
| 138 | + the string length is exactly that number of characters. For slices, |
| 139 | + arrays, and maps, validates the number of items. (Usage: len=10) |
| 140 | + max |
| 141 | + For numbers, max will ensure that the value is |
| 142 | + less than or equal to the parameter given. For strings, it checks |
| 143 | + that the string length is at most that number of characters. For |
| 144 | + slices, arrays, and maps, validates the number of items. (Usage: max=10) |
| 145 | + min |
| 146 | + For numbers, min will ensure that the value is |
| 147 | + greater or equal to the parameter given. For strings, it checks that |
| 148 | + the string length is at least that number of characters. For slices, |
| 149 | + arrays, and maps, validates the number of items. (Usage: min=10) |
| 150 | +
|
| 151 | + required |
| 152 | + This validates that the value is not the data types default value. |
| 153 | + For numbers ensures value is not zero. For strings ensures value is |
| 154 | + not "". For slices, arrays, and maps, ensures the length is not zero. |
| 155 | + (Usage: required) |
| 156 | +
|
| 157 | +Validator notes: |
| 158 | +
|
| 159 | + regex |
| 160 | + a regex validator won't be added because commas and = signs can be part of |
| 161 | + a regex which conflict with the validation definitions, although workarounds |
| 162 | + can be made, they take away from using pure regex's. Furthermore it's quick |
| 163 | + and dirty but the regex's become harder to maintain and are not reusable, so |
| 164 | + it's as much as a programming philosiphy as anything. |
| 165 | +
|
| 166 | + In place of this new validator functions should be created; a regex can be |
| 167 | + used within the validator function and even be precompiled for better efficiency. |
| 168 | +
|
| 169 | + And the best reason, you can sumit a pull request and we can keep on adding to the |
| 170 | + validation library of this package! |
| 171 | +
|
| 172 | +Panics |
| 173 | +
|
| 174 | +This package panics when bad input is provided, this is by design, bad code like that should not make it to production. |
| 175 | +
|
| 176 | + type Test struct { |
| 177 | + TestField string `validate:"nonexistantfunction=1"` |
| 178 | + } |
| 179 | +
|
| 180 | + t := &Test{ |
| 181 | + TestField: "Test" |
| 182 | + } |
| 183 | +
|
| 184 | + validator.ValidateStruct(t) // this will panic |
| 185 | +*/ |
24 | 186 | package validator |
0 commit comments