2014-07-03 21:19:06 +04:00
|
|
|
package binding
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"encoding/xml"
|
2014-07-05 01:28:50 +04:00
|
|
|
"errors"
|
|
|
|
"net/http"
|
|
|
|
"reflect"
|
|
|
|
"strings"
|
2014-07-03 21:19:06 +04:00
|
|
|
)
|
|
|
|
|
|
|
|
type (
|
|
|
|
Binding interface {
|
2014-07-05 01:28:50 +04:00
|
|
|
Bind(*http.Request, interface{}) error
|
2014-07-03 21:19:06 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// JSON binding
|
|
|
|
jsonBinding struct{}
|
|
|
|
|
2014-07-05 01:28:50 +04:00
|
|
|
// XML binding
|
2014-07-03 21:19:06 +04:00
|
|
|
xmlBinding struct{}
|
2014-07-05 01:28:50 +04:00
|
|
|
|
|
|
|
// // form binding
|
|
|
|
formBinding struct{}
|
2014-07-03 21:19:06 +04:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
JSON = jsonBinding{}
|
|
|
|
XML = xmlBinding{}
|
2014-07-05 01:28:50 +04:00
|
|
|
Form = formBinding{} // todo
|
2014-07-03 21:19:06 +04:00
|
|
|
)
|
|
|
|
|
2014-07-05 01:28:50 +04:00
|
|
|
func (_ jsonBinding) Bind(req *http.Request, obj interface{}) error {
|
|
|
|
decoder := json.NewDecoder(req.Body)
|
|
|
|
if err := decoder.Decode(obj); err == nil {
|
|
|
|
return Validate(obj)
|
|
|
|
} else {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (_ xmlBinding) Bind(req *http.Request, obj interface{}) error {
|
|
|
|
decoder := xml.NewDecoder(req.Body)
|
|
|
|
if err := decoder.Decode(obj); err == nil {
|
|
|
|
return Validate(obj)
|
|
|
|
} else {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (_ formBinding) Bind(req *http.Request, obj interface{}) error {
|
|
|
|
return nil
|
2014-07-03 21:19:06 +04:00
|
|
|
}
|
|
|
|
|
2014-07-05 01:28:50 +04:00
|
|
|
func Validate(obj interface{}) error {
|
|
|
|
|
|
|
|
typ := reflect.TypeOf(obj)
|
|
|
|
val := reflect.ValueOf(obj)
|
|
|
|
|
|
|
|
if typ.Kind() == reflect.Ptr {
|
|
|
|
typ = typ.Elem()
|
|
|
|
val = val.Elem()
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < typ.NumField(); i++ {
|
|
|
|
field := typ.Field(i)
|
|
|
|
fieldValue := val.Field(i).Interface()
|
|
|
|
zero := reflect.Zero(field.Type).Interface()
|
|
|
|
|
|
|
|
// Validate nested and embedded structs (if pointer, only do so if not nil)
|
|
|
|
if field.Type.Kind() == reflect.Struct ||
|
|
|
|
(field.Type.Kind() == reflect.Ptr && !reflect.DeepEqual(zero, fieldValue)) {
|
|
|
|
if err := Validate(fieldValue); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.Index(field.Tag.Get("binding"), "required") > -1 {
|
|
|
|
if reflect.DeepEqual(zero, fieldValue) {
|
|
|
|
name := field.Name
|
|
|
|
if j := field.Tag.Get("json"); j != "" {
|
|
|
|
name = j
|
|
|
|
} else if f := field.Tag.Get("form"); f != "" {
|
|
|
|
name = f
|
|
|
|
}
|
|
|
|
return errors.New("Required " + name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
2014-07-03 21:19:06 +04:00
|
|
|
}
|