fix(binding): Expose validator engine used by the default Validator (#1277)
* fix(binding): Expose validator engine used by the default Validator
- Add func ValidatorEngine for returning the underlying validator engine used
  in the default StructValidator implementation.
- Remove the function RegisterValidation from the StructValidator interface
  which made it immpossible to use a StructValidator implementation without the
  validator.v8 library.
- Update and rename test for registering validation
  Test{RegisterValidation => ValidatorEngine}.
- Update readme and example for registering custom validation.
- Add example for registering struct level validation.
- Add documentation for the following binding funcs/types:
  - Binding interface
  - StructValidator interface
  - Validator instance
  - Binding implementations
  - Default func
* fix(binding): Move validator engine getter inside interface
* docs: rm date cmd from custom validation demo
			
			
This commit is contained in:
		| @ -6,8 +6,6 @@ package binding | ||||
|  | ||||
| import ( | ||||
| 	"net/http" | ||||
|  | ||||
| 	"gopkg.in/go-playground/validator.v8" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| @ -23,11 +21,18 @@ const ( | ||||
| 	MIMEMSGPACK2          = "application/msgpack" | ||||
| ) | ||||
|  | ||||
| // Binding describes the interface which needs to be implemented for binding the | ||||
| // data present in the request such as JSON request body, query parameters or | ||||
| // the form POST. | ||||
| type Binding interface { | ||||
| 	Name() string | ||||
| 	Bind(*http.Request, interface{}) error | ||||
| } | ||||
|  | ||||
| // StructValidator is the minimal interface which needs to be implemented in | ||||
| // order for it to be used as the validator engine for ensuring the correctness | ||||
| // of the reqest. Gin provides a default implementation for this using | ||||
| // https://github.com/go-playground/validator/tree/v8.18.2. | ||||
| type StructValidator interface { | ||||
| 	// ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right. | ||||
| 	// If the received type is not a struct, any validation should be skipped and nil must be returned. | ||||
| @ -36,14 +41,18 @@ type StructValidator interface { | ||||
| 	// Otherwise nil must be returned. | ||||
| 	ValidateStruct(interface{}) error | ||||
|  | ||||
| 	// RegisterValidation adds a validation Func to a Validate's map of validators denoted by the key | ||||
| 	// NOTE: if the key already exists, the previous validation function will be replaced. | ||||
| 	// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation | ||||
| 	RegisterValidation(string, validator.Func) error | ||||
| 	// Engine returns the underlying validator engine which powers the | ||||
| 	// StructValidator implementation. | ||||
| 	Engine() interface{} | ||||
| } | ||||
|  | ||||
| // Validator is the default validator which implements the StructValidator | ||||
| // interface. It uses https://github.com/go-playground/validator/tree/v8.18.2 | ||||
| // under the hood. | ||||
| var Validator StructValidator = &defaultValidator{} | ||||
|  | ||||
| // These implement the Binding interface and can be used to bind the data | ||||
| // present in the request to struct instances. | ||||
| var ( | ||||
| 	JSON          = jsonBinding{} | ||||
| 	XML           = xmlBinding{} | ||||
| @ -55,6 +64,8 @@ var ( | ||||
| 	MsgPack       = msgpackBinding{} | ||||
| ) | ||||
|  | ||||
| // Default returns the appropriate Binding instance based on the HTTP method | ||||
| // and the content type. | ||||
| func Default(method, contentType string) Binding { | ||||
| 	if method == "GET" { | ||||
| 		return Form | ||||
|  | ||||
| @ -28,9 +28,13 @@ func (v *defaultValidator) ValidateStruct(obj interface{}) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (v *defaultValidator) RegisterValidation(key string, fn validator.Func) error { | ||||
| // Engine returns the underlying validator engine which powers the default | ||||
| // Validator instance. This is useful if you want to register custom validations | ||||
| // or struct level validations. See validator GoDoc for more info - | ||||
| // https://godoc.org/gopkg.in/go-playground/validator.v8 | ||||
| func (v *defaultValidator) Engine() interface{} { | ||||
| 	v.lazyinit() | ||||
| 	return v.validate.RegisterValidation(key, fn) | ||||
| 	return v.validate | ||||
| } | ||||
|  | ||||
| func (v *defaultValidator) lazyinit() { | ||||
|  | ||||
| @ -10,6 +10,9 @@ import ( | ||||
| 	"github.com/gin-gonic/gin/json" | ||||
| ) | ||||
|  | ||||
| // EnableDecoderUseNumber is used to call the UseNumber method on the JSON | ||||
| // Decoder instance. UseNumber causes the Decoder to unmarshal a number into an | ||||
| // interface{} as a Number instead of as a float64. | ||||
| var EnableDecoderUseNumber = false | ||||
|  | ||||
| type jsonBinding struct{} | ||||
|  | ||||
| @ -214,11 +214,14 @@ func notOne( | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func TestRegisterValidation(t *testing.T) { | ||||
| func TestValidatorEngine(t *testing.T) { | ||||
| 	// This validates that the function `notOne` matches | ||||
| 	// the expected function signature by `defaultValidator` | ||||
| 	// and by extension the validator library. | ||||
| 	err := Validator.RegisterValidation("notone", notOne) | ||||
| 	engine, ok := Validator.Engine().(*validator.Validate) | ||||
| 	assert.True(t, ok) | ||||
|  | ||||
| 	err := engine.RegisterValidation("notone", notOne) | ||||
| 	// Check that we can register custom validation without error | ||||
| 	assert.Nil(t, err) | ||||
|  | ||||
| @ -228,6 +231,6 @@ func TestRegisterValidation(t *testing.T) { | ||||
|  | ||||
| 	// Check that we got back non-nil errs | ||||
| 	assert.NotNil(t, errs) | ||||
| 	// Check that the error matches expactation | ||||
| 	// Check that the error matches expectation | ||||
| 	assert.Error(t, errs, "", "", "notone") | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user