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

Getting the correct field name on bind validation errors #4102

Open
OranShuster opened this issue Nov 20, 2024 · 4 comments
Open

Getting the correct field name on bind validation errors #4102

OranShuster opened this issue Nov 20, 2024 · 4 comments

Comments

@OranShuster
Copy link

OranShuster commented Nov 20, 2024

Description

When gettig an error back from ShouldBind* methods, im looking for a way to return to the user the correct field names
Looking at the ValidationErrors and FieldError structs i don't see the actual name of the query param
Is this a validator limitation or can this be solved by gin?

Side note - this part of the gin documentation is a bit lacking. it would be very beneficial to add an example about using ValidationErrors , instead of just a normal go error, when binding

How to reproduce

package main

import (
	"errors"
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
)

type queryTestStruct struct {
	Param1 string `form:"othername" binding:"required"`
}

func main() {
	r := gin.Default()
	r.GET("/testQuery", func(c *gin.Context) {
		var params queryTestStruct
		err := c.ShouldBindQuery(&params)
		if err != nil {
			var ve validator.ValidationErrors
			if errors.As(err, &ve) {
				out := map[string]interface{}{}
				for _, fe := range ve {
					fieldName := fe.Field()
					error := fe.Error()
					out[fieldName] = error
				}
				c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errors": out})
			}
			return
		}
		c.JSON(200, "No error")
	})
	r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}

Expectations

I expect to have some way to get from the FieldError struct the actual expected query param name: othername

Actual result

$ curl --location 'localhost:8080/testQuery'
{
    "errors": {
        "Param1": "Key: 'queryTestStruct.Param1' Error:Field validation for 'Param1' failed on the 'required' tag"
    }
}

Environment

  • go version: 1.23
  • gin version (or commit ref): v1.10.0
  • operating system: Windows 11
@jerryyummy
Copy link

you do not include the parameter, should use :curl -G "http://localhost:8080/testQuery" --data-urlencode "othername=your_value"

@OranShuster
Copy link
Author

OranShuster commented Nov 22, 2024

you do not include the parameter, should use :curl -G "http://localhost:8080/testQuery" --data-urlencode "othername=your_value"

you are misunderstanding my question, im talking about query parameters error handling. obviously if ill send the parameter i won't get any error

@GenJi77JYXC
Copy link

Maybe you can solve this problem using reflection

Here are some of my solutions

package main

import (
	"errors"
	"fmt"
	"github.com/go-playground/validator/v10"
	"net/http"
	"reflect"

	"github.com/gin-gonic/gin"
)

type queryTestStruct struct {
	Param1 string `form:"othername" binding:"required"`
}

func main() {
	r := gin.Default()
	r.GET("/testQuery", func(c *gin.Context) {
		var params queryTestStruct
		err := c.ShouldBindQuery(&params)
		if err != nil {
			rType := reflect.TypeOf(new(queryTestStruct)).Elem()
			
			var ve validator.ValidationErrors
			if errors.As(err, &ve) {
				out := map[string]interface{}{}
				for _, fe := range ve {
					fieldName := fe.Field()
					param, ok := rType.FieldByName(fieldName)
					if ok {
						fmt.Println(param.Tag.Get("form"))//  // Get param's correct field name
					}
					error := fe.Error()
					out[fieldName] = error
					out["tagName"] = param.Tag.Get("form")
				}
				c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errors": out})
			}
			return
		}
		c.JSON(200, "No error")
	})
	r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}

Actual result

curl : {"errors":{"Param1":"Key: 'queryTestStruct.Param1' Error:Field validation for 'Param1' failed on the 'required' tag","tagName":"othername"}}

I used the tagName field to return the information you want

@jakubtomany
Copy link

That's great there is a workaround with reflection, however, it would be great if gin binding package handles it correctly by registering a TagNameFunc as mentioned here: go-playground/validator#681 (comment)

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

4 participants