govalidator
govalidator copied to clipboard
Option to report struct errors based on json field name
Hi,
Quite often structs are loaded from json using the standard json go functionality, i.e a struct definition below is quite common:
type User struct {
FirstName string `json:"first_name" valid:"required"`
LastName string `json:"first_name" valid:"required"`
}
Assuming we use the govalidator to validate our struct, it would be very handy to have the option to be able to specify that we would rather have error messages report fields names based on the json field name rather than the struct name per se.
i.e. instead of
FirstName: non zero value required
rather
first_name: non zero value required
Is this possible?
+1!!!!
If the intent is make the messages more user friendly I think that would be better use a field for these only purpose.
Hmmm i see your point and in some ways it is more flexible. But also the the json
tag is what the user will practically see for any restful JSON applications, which I believe will be a alot of use cases.
Could we potentially have some way of specifying a custom tag field?
We wanted the same thing, we ended up using reflect
to get the validation subject struct fields, extract their json
tags to get the field name we want to return in responses, something like this:
func ValidationError(ctx echo.Context, s interface{}, err error) error {
switch err.(type) {
case govalidator.Errors:
// Use reflect to get the raw struct element
typ := reflect.TypeOf(s).Elem()
if typ.Kind() != reflect.Struct {
return UnexpectedError(ctx, errors.New("validation subject is not a struct"))
}
// This is will contain the errors we return back to user
errs := map[string]string{}
// Errors found by the validator
errsByField := govalidator.ErrorsByField(err.(govalidator.Errors))
// Loop over our struct fields
for i := 0; i < typ.NumField(); i++ {
// Get the field
f := typ.Field(i)
// Do we have an error for the field
e, ok := errsByField[f.Name]
if ok {
// Try and get the `json` struct tag
name := strings.Split(f.Tag.Get("json"), ",")[0]
// If the name is - we should ignore the field
if name == "-" {
continue
}
// If the name is not blank we add it our error map
if name != "" {
errs[name] = e
continue
}
// Finall if all else has failed just add the raw field name to the
// error map
errs[f.Name] = e
}
}
// Return the validation error
mapper := &Errors{Message: "Validation Error", Errors: errs}
return ErrorHandler(422, mapper, ctx)
}
// If the error type is not a govalidator.Errors, return a 500
return UnexpectedError(
ctx,
fmt.Errorf("Expected govalidator.Errors, got %s", reflect.TypeOf(err)))
}
@krak3n could you put your example into pull request with sample of usage and small note in docs please?
@asaskevich sure, I'll try and do it over the weekend 😃
Looking forward to this PR.
Is it just going to use the json:"value"
as it's field name, or perhaps different approach will be taken?
Thanks.
@paroxp I didn't get to it last weekend but hopefully this weekend, it's just going to be documentation how how you could use reflection to get the json
, xml
or what ever other struct
tag to get the field name you want to use for the error value.
do we have updates or solution?
What about nested field names?
If we validate the following, we get Name: invalid_alphanum does not validate as alphanum
. However, we cannot identify which failed when nested fields contain the same name.
type Resource struct {
Name string `json:"name" valid:"alphanum"`
Version string `json:"version" valid:"required"`
Env struct {
Name string `json:"name" valid:"alphanum"`
Value string `json:"value" valid:"required"`
}
}
@retr0h it should return something like Env.Name: invalid_alphanum does not validate as alphanum
or Env.name ...
?
^ Yes, that would be the expected behavior, however is not the case currently
@asaskevich *
Hello guys! I forked this package cause owner disappeared. Hope, he will be back, but it would be easier to merge these changes back if he is back Link to my repo: create issue there and we'll discuss it.