package api import ( "encoding/json" "net/http" validator "gopkg.in/go-playground/validator.v9" ) const ( ErrCodeMalformedRequest ErrorCode = "malformed-request" ErrCodeInvalidRequest ErrorCode = "invalid-request" ErrCodeInvalidFieldValue ErrorCode = "invalid-field-value" ) // Bind parses and bind the request body to the given target // Bind wil also validates the received data with a validator instance. // If the data does not match the target constraints, an ErrorResponse will be // sent back. // See gopkg.in/go-playground/validator.v9 for more informations about data // validation. func Bind(w http.ResponseWriter, r *http.Request, target interface{}) (ok bool) { if err := parseBody(r, target); err != nil { ErrorResponse( w, http.StatusBadRequest, ErrCodeMalformedRequest, nil, ) return false } validate := validator.New() if err := validate.Struct(target); err != nil { handleValidateError(w, err) return false } return true } func parseBody(r *http.Request, target interface{}) error { decoder := json.NewDecoder(r.Body) if err := decoder.Decode(target); err != nil { return err } return nil } type fieldError struct { Field string Tag string Param string } func handleValidateError(w http.ResponseWriter, err error) { if validationErrors, ok := err.(validator.ValidationErrors); ok { fields := make([]fieldError, 0) for _, e := range validationErrors { fields = append(fields, fieldError{ Field: e.Field(), Tag: e.Tag(), Param: e.Param(), }) } ErrorResponse( w, http.StatusBadRequest, ErrCodeInvalidFieldValue, map[string]interface{}{ "Fields": fields, }, ) return } ErrorResponse( w, http.StatusBadRequest, ErrCodeInvalidRequest, nil, ) }