Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

map[string]*valueError is private so i cannot return it #28

Open
khanakia opened this issue Apr 24, 2024 · 4 comments
Open

map[string]*valueError is private so i cannot return it #28

khanakia opened this issue Apr 24, 2024 · 4 comments

Comments

@khanakia
Copy link

khanakia commented Apr 24, 2024

I have func and i want to return errors how do I do that as valueError is private I do not want to JSON marshal unnecessarily and then unmarshal again to a custom struct?

func RegisterValidate() map[string]*valueError {
	val := valgo.Is(
		valgo.String("Bob", "full_name").Not().Blank().OfLengthBetween(4, 20),
		valgo.Number(17, "age").GreaterThan(18),
	)
	if !val.Valid() {
		return val.Errors() // ???
	}

     return nil
}
@carlosforero
Copy link
Member

carlosforero commented Apr 25, 2024

Hi @khanakia,

Thank you so much for reporting the issue you're experiencing. I've been considering making valueError public to increase the library's flexibility. However, I also aim to maintain a minimal API interface to help ensure that code using Valgo remains concise and easy to manage for external libraries.

Valgo currently exposes a public valgo.Error class, which is returned by the Error() function of the validation session. The valgo.Error class provides a Errors() function that returns a map you're familiar with. This allows access to the public functions Messages(), Title(), and Messages() of *valgo.Error.

Here's an example with your code:

func RegisterValidate() *valgo.Error {
    val := valgo.Is(
        valgo.String("Bob", "full_name").Not().Blank().OfLengthBetween(4, 20),
        valgo.Number(17, "age").GreaterThan(18),
    )
    if !val.Valid() {
        return val.Error().(*valgo.Error)
    }
    return nil
}

func main() {
    err := RegisterValidate()
    if err != nil {
        fmt.Println("full_name", err.Errors()["full_name"].Messages())
        fmt.Println("age", err.Errors()["age"].Messages())
    }
}

Please, let me know if this makes sense to you, and if you see this as Go-programmer-friendly code.

On other hand, I'm concerned that the .Error() and .Errors() functions might be confusing. Perhaps renaming Errors() to ErrorsMap() could clarify their different purposes. Of course, I would add the ErrorsMap() function and mark Errors() as deprecated until we reach version 1.0. What do you think about this change? Would it make the library more expressive?

Looking forward to your feedback.

@khanakia
Copy link
Author

Anyway, i made it work by following the exact workaround you proposed.

I am using graphql and when just a return nil. error it shows the generic message like There is an error message

So I had to create a wrapper just to make the errors meaning full on the front end.

Maybe if possible somehow we could get the first error message returned instead of just a generic message.

Thanks

@jazoom
Copy link

jazoom commented Jun 9, 2024

I find this confusing too, but I'm new to Go so that probably has a lot to do with it. I also have been trying to figure out how to avoid marshalling the errors to JSON. I use HTMX with a RESTful API, so JSON is not passed anywhere.

Thanks for the great library. I think it's what I've been searching for.

@jazoom
Copy link

jazoom commented Jun 9, 2024

Here's my workaround. It seems a very convoluted way of getting the error messages without using JSON.

type postInput struct {
	GivenName  string
	Password   string
}

// Validate the input values and return a boolean indicating whether
// the input is valid, as well as a map of error messages if the input is invalid
func inputValidator(input *postInput) (bool, map[string]string) {
	val := v.Is(
		v.String(input.GivenName, "given name").Not().Blank().OfLengthBetween(1, 50),
		v.String(input.Password, "password").Not().Blank().MinLength(10),
	)

	if !val.Valid() {
		messageMap := make(map[string]string)
		valErrors := val.Error().(*valgo.Error).Errors()
		for key, value := range valErrors {
			messageMap[key] = value.Messages()[0]
		}
		return false, messageMap
	}

	return true, nil
}

// Used like this
ok, messageMap := inputValidator(<input>)
if !ok {
for field, message := range messageMap {
	fmt.Printf("%v: %v\n", field, message)
}

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

No branches or pull requests

3 participants