diff --git a/binding/form_mapping.go b/binding/form_mapping.go index 55435b94..91b3ee26 100644 --- a/binding/form_mapping.go +++ b/binding/form_mapping.go @@ -26,6 +26,29 @@ var ( ErrConvertToMapString = errors.New("can not convert to map of strings") ) +type FieldError struct { + Field string + Err error +} + +func NewFieldError(field string, err error) error { + if err == nil { + return nil + } + return &FieldError{ + Field: field, + Err: err, + } +} + +func (e *FieldError) Error() string { + return fmt.Sprintf("field %q error: %s", e.Field, e.Err) +} + +func (e *FieldError) Unwrap() error { + return e.Err +} + func mapURI(ptr any, m map[string][]string) error { return mapFormByTag(ptr, m, "uri") } @@ -161,7 +184,11 @@ func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter } } - return setter.TrySet(value, field, tagValue, setOpt) + ok, err := setter.TrySet(value, field, tagValue, setOpt) + if err != nil { + return ok, NewFieldError(tagValue, err) + } + return ok, nil } func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSet bool, err error) { diff --git a/binding/form_mapping_test.go b/binding/form_mapping_test.go index acea8f77..3b671358 100644 --- a/binding/form_mapping_test.go +++ b/binding/form_mapping_test.go @@ -5,6 +5,7 @@ package binding import ( + "errors" "reflect" "testing" "time" @@ -124,7 +125,7 @@ func TestMappingUnknownFieldType(t *testing.T) { err := mappingByPtr(&s, formSource{"U": {"unknown"}}, "form") assert.Error(t, err) - assert.Equal(t, errUnknownType, err) + assert.Equal(t, &FieldError{"U", errUnknownType}, err) } func TestMappingURI(t *testing.T) { @@ -321,3 +322,20 @@ func TestMappingIgnoredCircularRef(t *testing.T) { err := mappingByPtr(&s, formSource{}, "form") assert.NoError(t, err) } + +func TestNewField(t *testing.T) { + assert.NoError(t, NewFieldError("foo", nil)) + + orig := errors.New("bad value") + err := NewFieldError("foo", orig) + if assert.Error(t, err) { + assert.Equal(t, `field "foo" error: bad value`, err.Error()) + + if fieldErr, ok := err.(*FieldError); assert.True(t, ok) { //nolint: errorlint + assert.Equal(t, fieldErr.Field, "foo") + assert.Equal(t, fieldErr.Err, orig) + } + + assert.Equal(t, orig, errors.Unwrap(err)) + } +}