Convert validation to use FieldPath

Before this change we have a mish-mash of ways to pass field names around for
error generation.  Sometimes string fieldnames, sometimes .Prefix(), sometimes
neither, often wrong names or not indexed when it should be.

Instead of that mess, this is part one of a couple of commits that will make it
more strongly typed and hopefully encourage correct behavior.  At least you
will have to think about field names, which is better than nothing.

It turned out to be really hard to do this incrementally.
This commit is contained in:
Tim Hockin
2015-11-04 13:52:14 -08:00
parent 102eced0b1
commit e6df0b1a24
19 changed files with 986 additions and 807 deletions

View File

@@ -121,61 +121,61 @@ func (t ErrorType) String() string {
// NewNotFoundError returns a *Error indicating "value not found". This is
// used to report failure to find a requested value (e.g. looking up an ID).
func NewNotFoundError(field string, value interface{}) *Error {
return &Error{ErrorTypeNotFound, field, value, ""}
func NewNotFoundError(field *FieldPath, value interface{}) *Error {
return &Error{ErrorTypeNotFound, field.String(), value, ""}
}
// NewRequiredError returns a *Error indicating "value required". This is used
// to report required values that are not provided (e.g. empty strings, null
// values, or empty arrays).
func NewRequiredError(field string) *Error {
return &Error{ErrorTypeRequired, field, "", ""}
func NewRequiredError(field *FieldPath) *Error {
return &Error{ErrorTypeRequired, field.String(), "", ""}
}
// NewDuplicateError returns a *Error indicating "duplicate value". This is
// used to report collisions of values that must be unique (e.g. names or IDs).
func NewDuplicateError(field string, value interface{}) *Error {
return &Error{ErrorTypeDuplicate, field, value, ""}
func NewDuplicateError(field *FieldPath, value interface{}) *Error {
return &Error{ErrorTypeDuplicate, field.String(), value, ""}
}
// NewInvalidError returns a *Error indicating "invalid value". This is used
// to report malformed values (e.g. failed regex match, too long, out of bounds).
func NewInvalidError(field string, value interface{}, detail string) *Error {
return &Error{ErrorTypeInvalid, field, value, detail}
func NewInvalidError(field *FieldPath, value interface{}, detail string) *Error {
return &Error{ErrorTypeInvalid, field.String(), value, detail}
}
// NewNotSupportedError returns a *Error indicating "unsupported value".
// This is used to report unknown values for enumerated fields (e.g. a list of
// valid values).
func NewNotSupportedError(field string, value interface{}, validValues []string) *Error {
func NewNotSupportedError(field *FieldPath, value interface{}, validValues []string) *Error {
detail := ""
if validValues != nil && len(validValues) > 0 {
detail = "supported values: " + strings.Join(validValues, ", ")
}
return &Error{ErrorTypeNotSupported, field, value, detail}
return &Error{ErrorTypeNotSupported, field.String(), value, detail}
}
// NewForbiddenError returns a *Error indicating "forbidden". This is used to
// report valid (as per formatting rules) values which would be accepted under
// some conditions, but which are not permitted by current conditions (e.g.
// security policy).
func NewForbiddenError(field string, value interface{}) *Error {
return &Error{ErrorTypeForbidden, field, value, ""}
func NewForbiddenError(field *FieldPath, value interface{}) *Error {
return &Error{ErrorTypeForbidden, field.String(), value, ""}
}
// NewTooLongError returns a *Error indicating "too long". This is used to
// report that the given value is too long. This is similar to
// NewInvalidError, but the returned error will not include the too-long
// value.
func NewTooLongError(field string, value interface{}, maxLength int) *Error {
return &Error{ErrorTypeTooLong, field, value, fmt.Sprintf("must have at most %d characters", maxLength)}
func NewTooLongError(field *FieldPath, value interface{}, maxLength int) *Error {
return &Error{ErrorTypeTooLong, field.String(), value, fmt.Sprintf("must have at most %d characters", maxLength)}
}
// NewInternalError returns a *Error indicating "internal error". This is used
// to signal that an error was found that was not directly related to user
// input. The err argument must be non-nil.
func NewInternalError(field string, err error) *Error {
return &Error{ErrorTypeInternal, field, nil, err.Error()}
func NewInternalError(field *FieldPath, err error) *Error {
return &Error{ErrorTypeInternal, field.String(), nil, err.Error()}
}
// ErrorList holds a set of errors.