feat(binding): support custom struct tag (#2720)
* feat(binding): support custom struct tag Add function `binding.MapFormWithTag` (#2719) * doc: add 'bind form-data with custom struct tag' Add 'Bind form-data request with custom struct and custom tag' section (#2719) * test(binding): add test for MapFromWithTag
This commit is contained in:
		
							
								
								
									
										55
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								README.md
									
									
									
									
									
								
							| @ -2021,6 +2021,61 @@ enough to call binding at once. | ||||
| can be called by `c.ShouldBind()` multiple times without any damage to | ||||
| performance (See [#1341](https://github.com/gin-gonic/gin/pull/1341)). | ||||
|  | ||||
| ### Bind form-data request with custom struct and custom tag | ||||
|  | ||||
| ```go | ||||
| const ( | ||||
| 	customerTag = "url" | ||||
| 	defaultMemory = 32 << 20 | ||||
| ) | ||||
|  | ||||
| type customerBinding struct {} | ||||
|  | ||||
| func (customerBinding) Name() string { | ||||
| 	return "form" | ||||
| } | ||||
|  | ||||
| func (customerBinding) Bind(req *http.Request, obj interface{}) error { | ||||
| 	if err := req.ParseForm(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := req.ParseMultipartForm(defaultMemory); err != nil { | ||||
| 		if err != http.ErrNotMultipart { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	if err := binding.MapFormWithTag(obj, req.Form, customerTag); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return validate(obj) | ||||
| } | ||||
|  | ||||
| func validate(obj interface{}) error { | ||||
| 	if binding.Validator == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return binding.Validator.ValidateStruct(obj) | ||||
| } | ||||
|  | ||||
| // Now we can do this!!! | ||||
| // FormA is a external type that we can't modify it's tag | ||||
| type FormA struct { | ||||
| 	FieldA string `url:"field_a"` | ||||
| } | ||||
|  | ||||
| func ListHandler(s *Service) func(ctx *gin.Context) { | ||||
| 	return func(ctx *gin.Context) { | ||||
| 		var urlBinding = customerBinding{} | ||||
| 		var opt FormA | ||||
| 		err := ctx.MustBindWith(&opt, urlBinding) | ||||
| 		if err != nil { | ||||
| 			... | ||||
| 		} | ||||
| 		... | ||||
| 	} | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### http2 server push | ||||
|  | ||||
| http.Pusher is supported only **go1.8+**. See the [golang blog](https://blog.golang.org/h2push) for detail information. | ||||
|  | ||||
| @ -34,6 +34,10 @@ func mapForm(ptr interface{}, form map[string][]string) error { | ||||
| 	return mapFormByTag(ptr, form, "form") | ||||
| } | ||||
|  | ||||
| func MapFormWithTag(ptr interface{}, form map[string][]string, tag string) error { | ||||
| 	return mapFormByTag(ptr, form, tag) | ||||
| } | ||||
|  | ||||
| var emptyField = reflect.StructField{} | ||||
|  | ||||
| func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error { | ||||
|  | ||||
| @ -145,6 +145,15 @@ func TestMappingForm(t *testing.T) { | ||||
| 	assert.Equal(t, int(6), s.F) | ||||
| } | ||||
|  | ||||
| func TestMapFormWithTag(t *testing.T) { | ||||
| 	var s struct { | ||||
| 		F int `externalTag:"field"` | ||||
| 	} | ||||
| 	err := MapFormWithTag(&s, map[string][]string{"field": {"6"}}, "externalTag") | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, int(6), s.F) | ||||
| } | ||||
|  | ||||
| func TestMappingTime(t *testing.T) { | ||||
| 	var s struct { | ||||
| 		Time      time.Time | ||||
|  | ||||
		Reference in New Issue
	
	Block a user