-
Notifications
You must be signed in to change notification settings - Fork 20
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
Gin example #3
Comments
Well that took a while to figure out.
and
did the job. Only other thing I could not solve, is how to actually use RegisterStructLevel without much code duplication. Wanted to wrap sql.NullString, as trim does not work (with RegisterCustomTypeFunc from the validator in mind) when used with this (because hard conversion to string in trim I assume). So it was easier to just rewrite TrimSpace with a type switch. |
Oh my, I'm my own grave digger. Years later, same question, I even find my own answer that does not help myself. Is there an example how to register mold with current gin, current validator v10? |
This is how I integrated
import (
"context"
"encoding/json"
"errors"
"io"
"net/http"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/mold/v4/modifiers"
)
var conform = modifiers.New()
// customJSONBinding is mostly same as Gin JSON Binding, but it transforms data after decoding and before validating
type customJSONBinding struct{}
func (customJSONBinding) Name() string {
return "supplier custom json binding"
}
func (customJSONBinding) Bind(req *http.Request, obj any) error {
if req == nil || req.Body == nil {
return errors.New("invalid request")
}
return decodeJSON(req.Body, obj)
}
func decodeJSON(r io.Reader, obj any) error {
decoder := json.NewDecoder(r)
if binding.EnableDecoderUseNumber {
decoder.UseNumber()
}
if binding.EnableDecoderDisallowUnknownFields {
decoder.DisallowUnknownFields()
}
if err := decoder.Decode(obj); err != nil {
return err
}
if err := transform(obj); err != nil {
return err
}
return validate(obj)
}
func transform(obj any) error {
if conform == nil {
return nil
}
return conform.Struct(context.Background(), obj)
}
func validate(obj any) error {
if binding.Validator == nil {
return nil
}
return binding.Validator.ValidateStruct(obj)
}
// You have to init an instance of `customJSONBinding` to use
var customJSON = customJSONBinding{}
type Request struct {
Email string `json:"email" mod:"trim" binding:"required,email"`
Name string `json:"name" mod:"trim" binding:"required"`
}
func myHandler(c *gin.Context) {
var req Request
if err := c.ShouldBindWith(&req, customJSON); err != nil {
// Do smt...
}
} |
The solution by @aupous worked. But, here is how I integrated Create the custom validator:// helpers/custom_validator_helper.go
package helpers
import (
"context"
"reflect"
"github.com/go-playground/mold/v4/modifiers"
"github.com/go-playground/validator/v10"
)
type CustomValidator struct {
validator *validator.Validate
}
func NewCustomValidator() *CustomValidator {
v := validator.New()
// Set the tag name to "binding", SetTagName allows for changing of the default tag name of 'validate'
v.SetTagName("binding")
// Register Tag Name Function to get json name as alternate names for StructFields.
v.RegisterTagNameFunc(func(fld reflect.StructField) string {
return fld.Tag.Get("json")
})
// Register custom validation tags if needed
v.RegisterValidation("customValidation", customValidationFunc)
return &CustomValidator{validator: v}
}
// ValidateStruct is called by Gin to validate the struct
func (cv *CustomValidator) ValidateStruct(obj interface{}) error {
// transform the object using mold before validating the struct
transformer := modifiers.New()
if err := transformer.Struct(context.Background(), obj); err != nil {
return err
}
// validate the struct
if err := cv.validator.Struct(obj); err != nil {
return err
}
return nil
}
// Engine is called by Gin to retrieve the underlying validation engine
func (cv *CustomValidator) Engine() interface{} {
return cv.validator
}
// Custom validation function
func customValidationFunc(fl validator.FieldLevel) bool {
// Custom validation logic here
return true
} Call the custom validator and override the binding validator:// main.go
package main
import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)
func main() {
router := gin.Default()
// Use custom validator
customValidator := helpers.NewCustomValidator() // Create a new instance of your custom validator
binding.Validator = customValidator // Set the binding.Validator to your custom validator
// Define your routes and handlers
// ...
// Run the server
router.Run(":8080")
} Then bind your Struct to the request using any of the default binding method type Request struct {
Email string `json:"email" mod:"trim" binding:"required,email"`
Name string `json:"name" mod:"trim" binding:"required"`
}
func myHandler(c *gin.Context) {
var req Request
if err := c.ShouldBind(&req); err != nil {
// Do smt...
}
} |
Do you have any example how to setup gin with v9 and modifiers/scrubbers?
Coming from other languages this seems like a nice way to handle it without writing a custom validator/processor for every user input. The only thing is, at least for me as a newish guy to golang, I have no clue how to integrate it with gin. The validator-upgrade.go is somewhat understandable, but I'm totally lost on how and where to hook into. Where does gin and the validator do the stuff and how do I inject mold.Transformer and actually execute it, prior to the validator (binding) run?
Can you give any hints or is there any help page I've missed?
The text was updated successfully, but these errors were encountered: