Giter VIP home page Giter VIP logo

Comments (4)

adrianrudnik avatar adrianrudnik commented on July 17, 2024 1

Well that took a while to figure out.

type defaultValidator struct {
	once      sync.Once
	validate  *validator.Validate
	modifiers *mold.Transformer
}

and

func (v *defaultValidator) lazyinit() {
	 ...
	v.modifiers = mold.New()
	v.modifiers.SetTagName("mod")
	v.modifiers.Register("trim", app.TrimSpace)
}

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.

from mold.

adrianrudnik avatar adrianrudnik commented on July 17, 2024

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?

from mold.

aupous avatar aupous commented on July 17, 2024

This is how I integrated mold with gin, u could check it out:

  1. Define your own Binding, similar to binding.JSONBinding of gin
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)
}
  1. Use your custom binding with ShouldBindWith to use mold
// 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...
    }
}

from mold.

victorybiz avatar victorybiz commented on July 17, 2024

The solution by @aupous worked.

But, here is how I integrated mold package with gin without rewriting/duplicating the entire binding package codes to create a custom binding for JSON and Form binding.
I created a custom Validator to transform the data object before validating a struct and replacing the binding validator with my custom validator.

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...
	}
}

from mold.

Related Issues (15)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.