Refactors binding validation

This commit is contained in:
Manu Mtz-Almeida 2015-05-31 16:18:50 +02:00
parent aa9078bc73
commit fecde9fed6
3 changed files with 69 additions and 28 deletions

View File

@ -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
} }

View File

@ -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")

View File

@ -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
}