Skip to content

Commit

Permalink
ServiceError.Field *string
Browse files Browse the repository at this point in the history
Some errors generated by Goa are specific to fields- this commit ensures
we populate `Field` of ServiceError when this is the case.

An example would be when a field has a validation like `MinLength(1)` or
similar, where the cause of the error is a specific part of the payload.

It's often useful to retrieve this field, so that people can use this
field to attach errors to the right form input, this being just one
important use case.
  • Loading branch information
lawrencejones committed Aug 14, 2021
1 parent 859e6a3 commit f97969f
Showing 1 changed file with 21 additions and 7 deletions.
28 changes: 21 additions & 7 deletions pkg/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ type (
Name string
// ID is a unique value for each occurrence of the error.
ID string
// Pointer to the field that caused this error, if appropriate
Field *string
// Message contains the specific error details.
Message string
// Is the error a timeout?
Expand Down Expand Up @@ -75,13 +77,15 @@ func DecodePayloadError(msg string) error {
// InvalidFieldTypeError is the error produced by the generated code when the
// type of a payload field does not match the type defined in the design.
func InvalidFieldTypeError(name string, val interface{}, expected string) error {
return PermanentError("invalid_field_type", "invalid value %#v for %q, must be a %s", val, name, expected)
return withField(name, PermanentError(
"invalid_field_type", "invalid value %#v for %q, must be a %s", val, name, expected))
}

// MissingFieldError is the error produced by the generated code when a payload
// is missing a required field.
func MissingFieldError(name, context string) error {
return PermanentError("missing_field", "%q is missing from %s", name, context)
return withField(name, PermanentError(
"missing_field", "%q is missing from %s", name, context))
}

// InvalidEnumValueError is the error produced by the generated code when the
Expand All @@ -92,21 +96,24 @@ func InvalidEnumValueError(name string, val interface{}, allowed []interface{})
for i, a := range allowed {
elems[i] = fmt.Sprintf("%#v", a)
}
return PermanentError("invalid_enum_value", "value of %s must be one of %s but got value %#v", name, strings.Join(elems, ", "), val)
return withField(name, PermanentError(
"invalid_enum_value", "value of %s must be one of %s but got value %#v", name, strings.Join(elems, ", "), val))
}

// InvalidFormatError is the error produced by the generated code when the value
// of a payload field does not match the format validation defined in the
// design.
func InvalidFormatError(name, target string, format Format, formatError error) error {
return PermanentError("invalid_format", "%s must be formatted as a %s but got value %q, %s", name, format, target, formatError.Error())
return withField(name, PermanentError(
"invalid_format", "%s must be formatted as a %s but got value %q, %s", name, format, target, formatError.Error()))
}

// InvalidPatternError is the error produced by the generated code when the
// value of a payload field does not match the pattern validation defined in the
// design.
func InvalidPatternError(name, target string, pattern string) error {
return PermanentError("invalid_pattern", "%s must match the regexp %q but got value %q", name, pattern, target)
return withField(name, PermanentError(
"invalid_pattern", "%s must match the regexp %q but got value %q", name, pattern, target))
}

// InvalidRangeError is the error produced by the generated code when the value
Expand All @@ -117,7 +124,8 @@ func InvalidRangeError(name string, target interface{}, value interface{}, min b
if !min {
comp = "lesser or equal"
}
return PermanentError("invalid_range", "%s must be %s than %d but got value %#v", name, comp, value, target)
return withField(name, PermanentError(
"invalid_range", "%s must be %s than %d but got value %#v", name, comp, value, target))
}

// InvalidLengthError is the error produced by the generated code when the value
Expand All @@ -128,7 +136,8 @@ func InvalidLengthError(name string, target interface{}, ln, value int, min bool
if !min {
comp = "lesser or equal"
}
return PermanentError("invalid_length", "length of %s must be %s than %d but got value %#v (len=%d)", name, comp, value, target, ln)
return withField(name, PermanentError(
"invalid_length", "length of %s must be %s than %d but got value %#v (len=%d)", name, comp, value, target, ln))
}

// NewErrorID creates a unique 8 character ID that is well suited to use as an
Expand Down Expand Up @@ -184,6 +193,11 @@ func (s *ServiceError) Error() string { return s.Message }
// ErrorName returns the error name.
func (s *ServiceError) ErrorName() string { return s.Name }

func withField(field string, err *ServiceError) *ServiceError {
err.Field = &field
return err
}

func newError(name string, timeout, temporary, fault bool, format string, v ...interface{}) *ServiceError {
return &ServiceError{
Name: name,
Expand Down

0 comments on commit f97969f

Please sign in to comment.