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 | can be called by `c.ShouldBind()` multiple times without any damage to | ||||||
| performance (See [#1341](https://github.com/gin-gonic/gin/pull/1341)). | 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 | ### http2 server push | ||||||
|  |  | ||||||
| http.Pusher is supported only **go1.8+**. See the [golang blog](https://blog.golang.org/h2push) for detail information. | 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") | 	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{} | var emptyField = reflect.StructField{} | ||||||
|  |  | ||||||
| func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error { | 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) | 	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) { | func TestMappingTime(t *testing.T) { | ||||||
| 	var s struct { | 	var s struct { | ||||||
| 		Time      time.Time | 		Time      time.Time | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user