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

validate tag not working in ShouldBindWith #3234

Closed
rahmathu opened this issue Jul 8, 2022 · 7 comments
Closed

validate tag not working in ShouldBindWith #3234

rahmathu opened this issue Jul 8, 2022 · 7 comments

Comments

@rahmathu
Copy link

rahmathu commented Jul 8, 2022

  • With issues:
    • Use the search tool before opening a new issue. - done
    • Please provide source code and commit sha if you found a bug. - done
    • Review existing issues and provide feedback or react to them. - Done

Description

I am trying to get the validation working in gin, with the validator package this validator tag works good. When i use it in gin it's not working and i am not sure if i am using it wrong or it's not working as a bug.
What all i did before opening this issue

  1. Took just the validator lib and did a small test case to make sure validator and tags are good
  2. Google or issue search does not show this validate tag being used and errors on it
  3. The looked at gin code to see that validation is triggered but not working in my case

I looked at the gin code and see here that ShouldBindWith() should eventually call this .
https://github.com/gin-gonic/gin/blob/4b68a5f12af4d6d2be83e1895f783d5dd5d5a148/binding/query.go
Once validate() is called it should validate using the validator package for the validate tag, which is not working as expected

validate:"omitempty,oneof=ASC DESC

Any help is appreciated on this

How to reproduce

package main

import (
	"log"
	"net/http"

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

// MyStruct ..
type MyStruct struct {
	Order string `form:"order,default=DESC" validate:"omitempty,oneof=ASC DESC"`
}

func startPage(c *gin.Context) {
	var person MyStruct
	if c.ShouldBindWith(&person, binding.Query) == nil {
		log.Println("====== Only Bind By Query String ======")
		log.Println(person.Order)
		c.String(http.StatusOK, "Success")
		return
		// log.Println(person.Address)
	}
	c.String(http.StatusBadRequest, "Failed")
	return
}

func main() {

	route := gin.Default()
	route.Any("/testing", startPage)
	route.Run(":8085")

        // This is just to show you guys that validate package works well throwing errors 
	// validate = validator.New()
	// validate.RegisterValidation("method", ValidateMyVal)

	// s := MyStruct{Order: "awesome"}

	// err := validate.Struct(s)
	// if err != nil {
	// 	fmt.Printf("Err(s):\n%+v\n", err)
	// } else {
	// 	fmt.Println("awesome validation looks good ")
	// }

	// s.Order = "not awesome"
	// err = validate.Struct(s)
	// if err != nil {
	// 	fmt.Printf("Err(s):\n%+v\n", err)
	// }

	// s.Order = "awesome mess"
	// err = validate.Struct(s)
	// if err != nil {
	// 	fmt.Printf("Err(s):\n%+v\n", err)
	// } else {
	// 	fmt.Println("mess validation looks good ")
	// }

}

Expectations

Here i expect the curl command to return me a StatusBadRequest and text "failed"

$ curl -G -d 'order=WRONG'  http://localhost:8085/testing
Failed

Actual result

Actual result is code StatusOk and "Success"

√ go_learning/learngo % curl -G -d 'order=WRONG'  http://localhost:8085/testing
Success         

Environment

  • go version: go1.17.6 darwin/amd64
  • gin version (or commit ref): github.com/gin-contrib/sse v0.1.0 // indirect
    github.com/gin-gonic/gin v1.8.1 // indirect
  • operating system: Mac OS - Big Sur 11.6.7
@rahmathu rahmathu changed the title validate tag now working in ShouldBindWith validate tag not working in ShouldBindWith Jul 8, 2022
@eleven26
Copy link

eleven26 commented Jul 10, 2022

You should use binding, not validate:

binding:"omitempty,oneof=ASC DESC"

Because gin has modified the validator's tagname :
default_validator.go#L95

func (v *defaultValidator) lazyinit() {
	v.once.Do(func() {
		v.validate = validator.New()
		v.validate.SetTagName("binding")
	})
}

@rahmathu
Copy link
Author

@eleven26 :
Thanks for the replies , some more questions to this

If i use binding in place of validate the "omitempty" does not work as it tries to unmarshall and expects it to be there. Do you know how may i do an omitempty and then oneof in the same tag. In case it will be a custom validator please give me an example with this sample code as i have tried may options but it's not wokring for me . Thanks in advance

@eleven26
Copy link

The omitempty in binding just means that if your request does not have this field in it, it will not check other validation rules.

@rahmathu
Copy link
Author

@eleven26 : Thanks for the confirmation, let me try out and get back. Till then please leave the issue open, i expect to close on this by this Friday . I will close the issue with comments my self if all goes well

@rahmathu
Copy link
Author

@eleven26 : Thanks all the things worked except on last thing on the validator for dates

type GeneralValidatorQueryParams struct {
	StartedAt time.Time `form:"startedAt" binding:"omitempty,required_with=EndedAt"`
	EndedAt   time.Time `form:"endedAt" binding:"omitempty,required_with=StartedAt,gtfield=StartedAt"`
}

In this case i was trying to use this for a GET request and these are query parameters.

  1. When i put query parameter as in the URL "/testGeneralInputValidator?endedAt=2009-01-06T12:59:59Z". I see that the validator is not showing an error when i have missed the startedAt field.
  2. I have also tried the reverse for "/testGeneralInputValidator?startedAt=2009-01-10T12:59:59Z" . I see that the validation does not fail for this query parameter. I am not sure why the tag required_with is not taking effect here with binding .

@eleven26
Copy link

  1. You should not use omitempty, because you already have required_with, which means you only check StartedAt when you pass EndedAt parameter, otherwise, validator will not check other validation rules when it sees omitempty:
type GeneralValidatorQueryParams struct {
	StartedAt time.Time `form:"startedAt" binding:"required_with=EndedAt"`
	EndedAt   time.Time `form:"endedAt" binding:"omitempty,required_with=StartedAt,gtfield=StartedAt"`
}

This may be a correct example.

  1. Same as before. If you use required_with you can't use omitempty anymore, if you add omitempty and the field doesn't exist required_with and other validation rules no longer work

You may not fully understand the usage of omitempty. The following is the description of omitempty in the official documentation:

validator.v9#hdr-Omit_Empty Allows conditional validation, for example if a field is not set with a value (Determined by the "required" validator) then other validation such as min or max won't run, but if a value is set validation will run.

@rahmathu
Copy link
Author

got it thanks, i will close the issue now :)

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