Search code examples
validationgogo-gin

Go gin validate input to exclude substring


I want to make sure an input does not include substring "organization", "forbidden" and is not equal to "foo" and "bar".

// cmd/httpd/handler/item_post.go

package handler

import (
  "net/http"
  "dummy-project/itemdata"

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

func ItemPost() gin.HandlerFunc {
  return func(c *gin.Context) {
    requestBody := itemdata.Item{}
    if err := c.ShouldBindJSON(&requestBody); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
        return
    }
    // insert Item object to DB
    c.JSON(http.StatusCreated, requestBody)
  }
}

Below is the struct I used for the POST request and inserting the DB record: // itemdata/item_data.go package itemdata

// Item struct used for POST request and inserting new item
type Item struct {
   ID           string `bson:"_id" json:"id"`
   Name string `bson:"name" json:"name" binding:"required,excludesrune=organizationforbidden,ne=foo,ne=bar"`
}

When I insert these values: foo -> validation failed on excludes rune

bar -> validation failed on ne

organization ->validation failed on excludes rune

orgfor -> validation failed on excludes rune

forbidden -> validation failed on excludes rune

BAR -> success

what i want: foo -> fail

bar -> fail

organization -> fail

orgfor -> success, because the organization and forbidden word is not whole

forbidden -> fail

BAR -> fail

how do i achieve this using go gin and go validator? thanks


Solution

  • It looks like you're trying to exclude an entire string, so the excludes validation would be more appropriate than excludesrune. A "rune" in Go is a Unicode Code Point, which you're probably more used to just calling a "character", so your validation as-written is probably failing any string which contains the letter o.

    Try this instead:

       Name string `bson:"name" json:"name" binding:"required,excludes=organization,excludes=forbidden,ne=foo,ne=bar"`
    

    EDIT: As noted in the comments, this doesn't meet your requirement of disallowing capitalized versions of the blocked strings. From what I can tell, you will need to do this with a custom validator:

    func caseInsensitiveExcludes(fl validator.FieldLevel) bool {
        lowerValue := strings.ToLower(fl.Field().String())
       
        if strings.Contains(lowerValue, fl.Param()) {
            return false
        }
    
        return true
    }
    
    validate.RegisterValidation("iexcludes", caseInsensitiveExcludes)
    

    Then try this field definition:

       Name string `bson:"name" json:"name" binding:"required,iexcludes=organization,iexcludes=forbidden,ne=foo,ne=bar"`