forked from mirror/gin
Refactors binding validation
This commit is contained in:
parent
aa9078bc73
commit
fecde9fed6
|
@ -4,12 +4,7 @@
|
||||||
|
|
||||||
package binding
|
package binding
|
||||||
|
|
||||||
import (
|
import "net/http"
|
||||||
"net/http"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"gopkg.in/bluesuncorp/validator.v5"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MIMEJSON = "application/json"
|
MIMEJSON = "application/json"
|
||||||
|
@ -26,7 +21,16 @@ type Binding interface {
|
||||||
Bind(*http.Request, interface{}) error
|
Bind(*http.Request, interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
var validate = validator.New("binding", validator.BakedInValidators)
|
type StructValidator interface {
|
||||||
|
// ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right.
|
||||||
|
// If the received type is not a struct, any validation should be skipped and nil must be returned.
|
||||||
|
// If the received type is a struct or pointer to a struct, the validation should be performed.
|
||||||
|
// If the struct is not valid or the validation itself fails, a descriptive error should be returned.
|
||||||
|
// Otherwise nil must be returned.
|
||||||
|
ValidateStruct(interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
var Validator StructValidator = &defaultValidator{}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
JSON = jsonBinding{}
|
JSON = jsonBinding{}
|
||||||
|
@ -49,28 +53,9 @@ func Default(method, contentType string) Binding {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidateField(f interface{}, tag string) error {
|
|
||||||
if err := validate.Field(f, tag); err != nil {
|
|
||||||
return error(err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Validate(obj interface{}) error {
|
func Validate(obj interface{}) error {
|
||||||
if kindOfData(obj) != reflect.Struct {
|
if Validator == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err := validate.Struct(obj); err != nil {
|
return Validator.ValidateStruct(obj)
|
||||||
return error(err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func kindOfData(data interface{}) reflect.Kind {
|
|
||||||
value := reflect.ValueOf(data)
|
|
||||||
valueType := value.Kind()
|
|
||||||
if valueType == reflect.Ptr {
|
|
||||||
valueType = value.Elem().Kind()
|
|
||||||
}
|
|
||||||
return valueType
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,24 @@ func TestBindingXML(t *testing.T) {
|
||||||
"<map><foo>bar</foo></map>", "<map><bar>foo</bar></map>")
|
"<map><foo>bar</foo></map>", "<map><bar>foo</bar></map>")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidationFails(t *testing.T) {
|
||||||
|
var obj FooStruct
|
||||||
|
req := requestWithBody("POST", "/", `{"bar": "foo"}`)
|
||||||
|
err := JSON.Bind(req, &obj)
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidationDisabled(t *testing.T) {
|
||||||
|
backup := Validator
|
||||||
|
Validator = nil
|
||||||
|
defer func() { Validator = backup }()
|
||||||
|
|
||||||
|
var obj FooStruct
|
||||||
|
req := requestWithBody("POST", "/", `{"bar": "foo"}`)
|
||||||
|
err := JSON.Bind(req, &obj)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func testFormBinding(t *testing.T, method, path, badPath, body, badBody string) {
|
func testFormBinding(t *testing.T, method, path, badPath, body, badBody string) {
|
||||||
b := Form
|
b := Form
|
||||||
assert.Equal(t, b.Name(), "form")
|
assert.Equal(t, b.Name(), "form")
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package binding
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"gopkg.in/bluesuncorp/validator.v5"
|
||||||
|
)
|
||||||
|
|
||||||
|
type defaultValidator struct {
|
||||||
|
once sync.Once
|
||||||
|
validate *validator.Validate
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ StructValidator = &defaultValidator{}
|
||||||
|
|
||||||
|
func (v *defaultValidator) ValidateStruct(obj interface{}) error {
|
||||||
|
if kindOfData(obj) == reflect.Struct {
|
||||||
|
v.lazyinit()
|
||||||
|
return v.validate.Struct(obj)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *defaultValidator) lazyinit() {
|
||||||
|
v.once.Do(func() {
|
||||||
|
v.validate = validator.New("binding", validator.BakedInValidators)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func kindOfData(data interface{}) reflect.Kind {
|
||||||
|
value := reflect.ValueOf(data)
|
||||||
|
valueType := value.Kind()
|
||||||
|
if valueType == reflect.Ptr {
|
||||||
|
valueType = value.Elem().Kind()
|
||||||
|
}
|
||||||
|
return valueType
|
||||||
|
}
|
Loading…
Reference in New Issue