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

got json.UnmarshalTypeError instead of validator.ValidationErrors #3135

Open
mahdimehrabi opened this issue May 1, 2022 · 3 comments
Open

Comments

@mahdimehrabi
Copy link

mahdimehrabi commented May 1, 2022

Description

I use ShouldBindJSON for validation and I have a model that has a field with the type float32 name 'salary' when I send string for field salary I expect to get a slice of errors of type go-playground/v10 validator.ValidationErrors or slice of json.UnmarshalTypeError but I get only *json.UnmarshalTypeError

How to reproduce

type User struct {
	Name   string  `json:"name" binding:"required"`
	Salary float32 `json:"salary" binding:"required"`
	Age uint8 `json:"age" binding:"required"`
}

func main() {
	r := gin.Default()
	r.POST("/users", func(c *gin.Context) {
		u := User{}
		if err := c.ShouldBindJSON(&u); err != nil {
			c.String(402, "type: %T", err)
			return
		}
		c.String(200, "good")
	})
	r.Run()
}

Expectations

it will be very nice if it return errors as validator.ValidationErrors

$ curl -X curl -X POST -H "Content-Type: application/json" -d '{"name":123,"salary":"5000","age":"22"}' http://localhost:8080/users
type: validator.ValidationErrors

or maybe return errors as slice of *json.UnmarshalTypeError so we can generate error messages for all in response

$ curl -X curl -X POST -H "Content-Type: application/json" -d '{"name":123,"salary":"5000","age":"22"}' http://localhost:8080/users
type:[]*json.UnmarshalTypeError

Actual result

it only returns an error for the first field so the user must send request 3 times to solve type problems of his entry

$ curl -X curl -X POST -H "Content-Type: application/json" -d '{"name":123,"salary":"5000","age":"22"}' http://localhost:8080/users
type: *json.UnmarshalTypeError

Environment

  • go version: 1.17.8
  • gin version (or commit ref): 1.7.7
  • operating system: ubuntu
@mahdimehrabi mahdimehrabi changed the title bad validation result for incorrect type(ShouldBindJSON) get json.UnmarshalTypeError instead of validator.ValidationErrors May 1, 2022
@mahdimehrabi mahdimehrabi changed the title get json.UnmarshalTypeError instead of validator.ValidationErrors got json.UnmarshalTypeError instead of validator.ValidationErrors May 1, 2022
@kszafran
Copy link
Contributor

kszafran commented May 4, 2022

Gin basically uses the encoding/json package to unmarshal the request body first, and then runs validation on it. In your case unmarshaling itself has failed. I don't think it's possible to convert json.UnmarshalTypeError to validator.ValidationErrors in all cases. The former error often has less information. (If I remember correctly, when unmarshaling time.Time fails, you're not even told what field caused the problem.)

@mahdimehrabi
Copy link
Author

mahdimehrabi commented May 4, 2022

so gin must use another package to unmarshal because I think it's a huge problem
if we have this model fields

	Name   string  `json:"name" binding:"required"`
	Salary float32 `json:"salary" binding:"required"`
	Age uint8 `json:"age" binding:"required"`

and the user sends a request with this data

{
name:123,
salary:"5000",
age:"20"
}

we can only show one of this fields has a problem and the user must send 3 requests and solve its problems one by one to understand all of his fields types are wrong
besides other problem

Can you contribute and fix this problem or suggest to me a solution to fix this in my project or suggest me an alternative for encoding/json package so I contribute and fix this problem

@kszafran
Copy link
Contributor

kszafran commented May 4, 2022

I'm not a maintainer of Gin, so it's up to you how you want to handle this. In my projects, I have a wrapper around Gin's ShouldBindJSON, which can handle both ValidationErrors and UnmarshalTypeError and I'm just accepting the limitation that I might not always be able to present the user with all the invalid fields at once.

There are many alternative JSON libraries out there, e.g. https://github.com/goccy/go-json and https://github.com/json-iterator/go. I think Gin even has support for jsoniter: https://github.com/gin-gonic/gin/blob/master/internal/json/jsoniter.go. I haven't tried using alternative JSON libs, though, so I don't know if they provide better error reporting or not. This article lists a few more JSON libs: https://www.pixelstech.net/article/1639285333-Popular-Golang-JSON-libraries-evaluation

Worst case scenario, you could try umarshaling twice. First to interface{}, where you can check that fields have the types you expect, and then a second time to the target type. It's not pretty, but it would be one way to approach this if it's critical to you.

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

2 participants