Skip to content

Conversation

@joshhsoj1902
Copy link

The ValidationErrors type is public, but inside its 2 functions it casts to the private fieldError. Since there is no way to access the fieldError outside this package it meant creating and using ValidationErrors outside this package was impossible.

My use case is for testing, I'm trying to test how my code behaves when various ValidationErrors are returned without needing to actually setup data to fail in the various ways.

Fixes Or Enhances # .

Make sure that you've checked the boxes below before you submit PR:

  • Tests exist or have been written that cover this particular change.

Change Details:

@go-playground/admins

The `ValidationErrors` type is public, but inside its 2 functions it casts to the private `fieldError`. Since there is no way to access the `fieldError` outside this package it meant creating and using `ValidationErrors` outside this package was impossible.

My use case is for testing, I'm trying to test how my code behaves when various `ValidationErrors` are returned without needing to actually setup data to fail in the various ways.
Translate also needed the `ns` field.
@coveralls
Copy link

Coverage Status

Coverage remained the same at 100.0% when pulling 4654fc2 on joshhsoj1902:patch-1 into 1fa3c8d on go-playground:v9.

Translate(ut ut.Translator) string

// Error returns the FieldError's error message
Error() string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @joshhsoj1902 thanks for the PR

I think that only this addition is necessary

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @joeybloggs, I might be doing something wrong on my end, But for me, it only works when I also change the *fieldError references to the interface. When I just add Error() string to the interface I still get this error thrown

panic: interface conversion: validator.FieldError is *validator.fakeFieldError, not *validator.fieldError

(that panic happens on line 51, fakeFieldError is my implentation of FieldError)

My understanding is that since line 51 is trying to cast to the private struct, the only way the casting will pass is if the object being cast was also made from that private struct. and since it's private, I have no way of actually doing that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll take a closer look, sorry for the delay I'm extremely busy

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem at all. If there is anything you would rather I do instead, let me know. I think there are a few ways to solve this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joshhsoj1902 would you be able to share your example, seems like the best place for me to start :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey Joey, sorry for the slow reply. I do plan on circling back and creating a small sample program for you. Time is always the issue. Things should slow down a bit for me after next week.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no worries I only get a couple hours at most to take care of my open source stuff lately, tis the holiday season.

@deankarn
Copy link
Contributor

Hey @joshhsoj1902 I would be very interested in seeing your example that fails, I was able to cast the error to the field error type, see modified simple example below; strangely enough, I was unable to cast to the interface type in the range itself, had to be after the variable was already extracted.

package main

import (
	"fmt"
	"reflect"

	validator "gopkg.in/go-playground/validator.v9"
)

// User contains user information
type User struct {
	FirstName      string     `validate:"required"`
	LastName       string     `validate:"required"`
	Age            uint8      `validate:"gte=0,lte=130"`
	Email          string     `validate:"required,email"`
	FavouriteColor string     `validate:"iscolor"`                // alias for 'hexcolor|rgb|rgba|hsl|hsla'
	Addresses      []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
}

// Address houses a users address information
type Address struct {
	Street string `validate:"required"`
	City   string `validate:"required"`
	Planet string `validate:"required"`
	Phone  string `validate:"required"`
}

// use a single instance of Validate, it caches struct info
var validate *validator.Validate

func main() {

	validate = validator.New()

	validateStruct()
	validateVariable()
}

func validateStruct() {

	address := &Address{
		Street: "Eavesdown Docks",
		Planet: "Persphone",
		Phone:  "none",
	}

	user := &User{
		FirstName:      "Badger",
		LastName:       "Smith",
		Age:            135,
		Email:          "[email protected]",
		FavouriteColor: "#000-",
		Addresses:      []*Address{address},
	}

	// returns nil or ValidationErrors ( []FieldError )
	err := validate.Struct(user)
	if err != nil {

		// this check is only needed when your code could produce
		// an invalid value for validation such as interface with nil
		// value most including myself do not usually have code like this.
		if _, ok := err.(*validator.InvalidValidationError); ok {
			fmt.Println(err)
			return
		}

		for _, err := range err.(validator.ValidationErrors) {
			e2 := err.(validator.FieldError)
			fmt.Println(reflect.TypeOf(e2))
			fmt.Println(e2.Namespace())
			fmt.Println(e2.Field())
			fmt.Println(e2.StructNamespace()) // can differ when a custom TagNameFunc is registered or
			fmt.Println(e2.StructField())     // by passing alt name to ReportError like below
			fmt.Println(e2.Tag())
			fmt.Println(e2.ActualTag())
			fmt.Println(e2.Kind())
			fmt.Println(e2.Type())
			fmt.Println(e2.Value())
			fmt.Println(e2.Param())
			fmt.Println()
		}

		// from here you can create your own error messages in whatever language you wish
		return
	}

	// save user to database
}

func validateVariable() {

	myEmail := "joeybloggs.gmail.com"

	errs := validate.Var(myEmail, "required,email")

	if errs != nil {
		fmt.Println(errs) // output: Key: "" Error:Field validation for "" failed on the "email" tag
		return
	}

	// email ok, move on
}

@deankarn
Copy link
Contributor

@joshhsoj1902 are you able to provide an example?

@joshhsoj1902
Copy link
Author

Hey @deankarn, Sorry for never getting back to you on this, I ended up changing projects and the code I was dealing with I no longer have access to. I would need to come up with a new example and honestly, I don't foresee myself having time to do that anytime soon.

I'm really sorry, I hate not being able to help out more :(.

Feel free to close this.

@deankarn
Copy link
Contributor

I you ever do find time or want to pursue again please don't hesitate to revive this @joshhsoj1902 :)

@DavidLarsKetch
Copy link
Contributor

I've also run into the desire to include the fieldError message when handling and passing along error messages from ValidationErrors; so I've opened a new PR with that small change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants