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

Undefined validation function 'exists' on field #2160

Closed
atifzia opened this issue Nov 29, 2019 · 5 comments
Closed

Undefined validation function 'exists' on field #2160

atifzia opened this issue Nov 29, 2019 · 5 comments

Comments

@atifzia
Copy link

atifzia commented Nov 29, 2019

Description

just upgraded from v1.4.0 to v1.5.0 and end up with internal server error on tag binding:"exists"

How to reproduce

package main

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

type User struct {
	FirstName *string `json:"fn" binding:"exists"` 
}

	
func main(){
	router := gin.Default()
	router.POST("/register", func(c *gin.Context) {
		var user User
		if err := c.BindJSON(&user); err != nil {
			c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
		            "error": "first name cannot be empty",
	               })
			return
		}
	})

	router.Run(":8080")
}	

Expectations

return 400 with error message only if field FirstName is empty otherwise 200

Actual result

2019/11/29 11:44:13 [Recovery] 2019/11/29 - 11:44:13 panic recovered:
Undefined validation function 'exists' on field 'FirstName'
/home/atif/go/src/github.com/go-playground/validator/cache.go:289 (0x7526b5)
        (*Validate).parseFieldTagsRecursive: panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, current.tag, fieldName)))
/home/atif/go/src/github.com/go-playground/validator/cache.go:150 (0x751319)
        (*Validate).extractStructCache: ctag, _ = v.parseFieldTagsRecursive(tag, fld.Name, "", false)
/home/atif/go/src/github.com/go-playground/validator/validator.go:37 (0x7577bd)
        (*validate).validateStruct: cs = v.v.extractStructCache(current, typ.Name())
/home/atif/go/src/github.com/go-playground/validator/validator_instance.go:304 (0x75d706)
        (*Validate).StructCtx: vd.validateStruct(ctx, top, val, val.Type(), vd.ns[0:0], vd.actualNs[0:0], nil)
/home/atif/go/src/github.com/go-playground/validator/validator_instance.go:277 (0x8eb6ed)
        (*Validate).Struct: return v.StructCtx(context.Background(), s)
/home/atif/go/src/github.com/gin-gonic/gin/binding/default_validator.go:30 (0x8eb6b7)
        (*defaultValidator).ValidateStruct: if err := v.validate.Struct(obj); err != nil {
/home/atif/go/src/github.com/gin-gonic/gin/binding/binding.go:113 (0x8ef50c)
        validate: return Validator.ValidateStruct(obj)
/home/atif/go/src/github.com/gin-gonic/gin/binding/json.go:55 (0x8ef4c3)
        decodeJSON: return validate(obj)
/home/atif/go/src/github.com/gin-gonic/gin/binding/json.go:37 (0x8ef337)
        jsonBinding.Bind: return decodeJSON(req.Body, obj)
/home/atif/go/src/github.com/gin-gonic/gin/context.go:660 (0x8fc007)
        (*Context).ShouldBindWith: return b.Bind(c.Request, obj)
/home/atif/go/src/github.com/gin-gonic/gin/context.go:603 (0x8fbfd1)
        (*Context).MustBindWith: if err := c.ShouldBindWith(obj, b); err != nil {
/home/atif/go/src/github.com/gin-gonic/gin/context.go:566 (0xba6269)
        (*Context).BindJSON: return c.MustBindWith(obj, binding.JSON)
/home/atif/go/src/gitlab.com/atif/project/handlers/user.go:32 (0xba622f)
        (*Server).RegisterUser: if err := c.BindJSON(&u); err != nil {
/home/atif/go/src/github.com/gin-gonic/gin/context.go:147 (0x8f9859)
        (*Context).Next: c.handlers[c.index](c)
/home/atif/go/src/gitlab.com/atif/project/middlewares/auth.go:32 (0xbb6963)
        Auth.func1: c.Next()
/home/atif/go/src/github.com/gin-gonic/gin/context.go:147 (0x8f9859)
        (*Context).Next: c.handlers[c.index](c)
/home/atif/go/src/github.com/gin-gonic/gin/recovery.go:83 (0x90d179)
        RecoveryWithWriter.func1: c.Next()
/home/atif/go/src/github.com/gin-gonic/gin/context.go:147 (0x8f9859)
        (*Context).Next: c.handlers[c.index](c)
/home/atif/go/src/github.com/gin-gonic/gin/logger.go:241 (0x90c2a0)
        LoggerWithConfig.func1: c.Next()
/home/atif/go/src/github.com/gin-gonic/gin/context.go:147 (0x8f9859)
        (*Context).Next: c.handlers[c.index](c)
/home/atif/go/src/github.com/gin-gonic/gin/gin.go:411 (0x90381c)
        (*Engine).handleHTTPRequest: c.Next()
/home/atif/go/src/github.com/gin-gonic/gin/gin.go:369 (0x902f1d)
        (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/local/go/src/net/http/server.go:2774 (0x6cf5f7)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/go/src/net/http/server.go:1878 (0x6cb1e0)
        (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/local/go/src/runtime/asm_amd64.s:1337 (0x45f010)
        goexit: BYTE    $0x90   // NOP

Environment

  • go version: go1.12.6
  • gin version (or commit ref): v1.5.0
  • operating system: linux/amd64
@cppdebug
Copy link

cppdebug commented Dec 6, 2019

Gin.v1.4.0 use validator.v8 for validation and gin.v1.5.0 use validator.v9;

So you can define the struct like this:
type User struct {
// FirstName *string json:"fn" binding:"exists"
FirstName *string json:"fn" binding:"required"
}

I have got the correct result;

@atifzia atifzia closed this as completed Mar 26, 2020
@sify21
Copy link

sify21 commented Aug 12, 2020

But required doesn't allow zero-value. see #491

@mohsenasm
Copy link

We should use *int if we want to allow zero-value. See this issue.

@lovababu
Copy link

lovababu commented May 2, 2021

How to validate optional fields, when they present only?

@AcrylicShrimp
Copy link

How to validate optional fields, when they present only?

@lovababu omitempty maybe?

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

6 participants