mirror of
https://github.com/gin-gonic/gin.git
synced 2025-10-16 21:32:11 +08:00
feat(json): json support param and query binding
This commit is contained in:
parent
1c48977cca
commit
c65a6b8f25
@ -30,7 +30,7 @@ const (
|
|||||||
// the form POST.
|
// the form POST.
|
||||||
type Binding interface {
|
type Binding interface {
|
||||||
Name() string
|
Name() string
|
||||||
Bind(*http.Request, any) error
|
Bind(*http.Request, any, ...Option) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// BindingBody adds BindBody method to Binding. BindBody is similar with Bind,
|
// BindingBody adds BindBody method to Binding. BindBody is similar with Bind,
|
||||||
|
@ -19,7 +19,7 @@ func (formBinding) Name() string {
|
|||||||
return "form"
|
return "form"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (formBinding) Bind(req *http.Request, obj any) error {
|
func (formBinding) Bind(req *http.Request, obj any, opts ...Option) error {
|
||||||
if err := req.ParseForm(); err != nil {
|
if err := req.ParseForm(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -36,7 +36,7 @@ func (formPostBinding) Name() string {
|
|||||||
return "form-urlencoded"
|
return "form-urlencoded"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (formPostBinding) Bind(req *http.Request, obj any) error {
|
func (formPostBinding) Bind(req *http.Request, obj any, opts ...Option) error {
|
||||||
if err := req.ParseForm(); err != nil {
|
if err := req.ParseForm(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ func (formMultipartBinding) Name() string {
|
|||||||
return "multipart/form-data"
|
return "multipart/form-data"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (formMultipartBinding) Bind(req *http.Request, obj any) error {
|
func (formMultipartBinding) Bind(req *http.Request, obj any, opts ...Option) error {
|
||||||
if err := req.ParseMultipartForm(defaultMemory); err != nil {
|
if err := req.ParseMultipartForm(defaultMemory); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ func (headerBinding) Name() string {
|
|||||||
return "header"
|
return "header"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (headerBinding) Bind(req *http.Request, obj any) error {
|
func (headerBinding) Bind(req *http.Request, obj any, opts ...Option) error {
|
||||||
|
|
||||||
if err := mapHeader(obj, req.Header); err != nil {
|
if err := mapHeader(obj, req.Header); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -24,16 +24,37 @@ var EnableDecoderUseNumber = false
|
|||||||
// keys which do not match any non-ignored, exported fields in the destination.
|
// keys which do not match any non-ignored, exported fields in the destination.
|
||||||
var EnableDecoderDisallowUnknownFields = false
|
var EnableDecoderDisallowUnknownFields = false
|
||||||
|
|
||||||
|
var EnableParamsAndQueryBinding = false
|
||||||
|
|
||||||
type jsonBinding struct{}
|
type jsonBinding struct{}
|
||||||
|
|
||||||
func (jsonBinding) Name() string {
|
func (jsonBinding) Name() string {
|
||||||
return "json"
|
return "json"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (jsonBinding) Bind(req *http.Request, obj any) error {
|
func (jsonBinding) Bind(req *http.Request, obj any, opts ...Option) error {
|
||||||
if req == nil || req.Body == nil {
|
if req == nil || req.Body == nil {
|
||||||
return errors.New("invalid request")
|
return errors.New("invalid request")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if EnableParamsAndQueryBinding {
|
||||||
|
o := &options{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
if err := opt(o); nil != err {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if params := o.params; len(params) > 0 {
|
||||||
|
b := new(bytes.Buffer)
|
||||||
|
if err := json.NewEncoder(b).Encode(params); nil != err {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := decodeJSON(b, obj); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return decodeJSON(req.Body, obj)
|
return decodeJSON(req.Body, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ func (msgpackBinding) Name() string {
|
|||||||
return "msgpack"
|
return "msgpack"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msgpackBinding) Bind(req *http.Request, obj any) error {
|
func (msgpackBinding) Bind(req *http.Request, obj any, opts ...Option) error {
|
||||||
return decodeMsgPack(req.Body, obj)
|
return decodeMsgPack(req.Body, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
binding/option.go
Normal file
15
binding/option.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package binding
|
||||||
|
|
||||||
|
type options struct {
|
||||||
|
params map[string]interface{}
|
||||||
|
query map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option func(opt *options) error
|
||||||
|
|
||||||
|
func WithParams(params map[string]interface{}) Option {
|
||||||
|
return func(opt *options) error {
|
||||||
|
opt.params = params
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,7 @@ func (protobufBinding) Name() string {
|
|||||||
return "protobuf"
|
return "protobuf"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b protobufBinding) Bind(req *http.Request, obj any) error {
|
func (b protobufBinding) Bind(req *http.Request, obj any, opts ...Option) error {
|
||||||
buf, err := ioutil.ReadAll(req.Body)
|
buf, err := ioutil.ReadAll(req.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -12,7 +12,7 @@ func (queryBinding) Name() string {
|
|||||||
return "query"
|
return "query"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (queryBinding) Bind(req *http.Request, obj any) error {
|
func (queryBinding) Bind(req *http.Request, obj any, opts ...Option) error {
|
||||||
values := req.URL.Query()
|
values := req.URL.Query()
|
||||||
if err := mapForm(obj, values); err != nil {
|
if err := mapForm(obj, values); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -26,7 +26,7 @@ func decodeToml(r io.Reader, obj any) error {
|
|||||||
return decoder.Decode(obj)
|
return decoder.Decode(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tomlBinding) Bind(req *http.Request, obj any) error {
|
func (tomlBinding) Bind(req *http.Request, obj any, opts ...Option) error {
|
||||||
return decodeToml(req.Body, obj)
|
return decodeToml(req.Body, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ func (xmlBinding) Name() string {
|
|||||||
return "xml"
|
return "xml"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (xmlBinding) Bind(req *http.Request, obj any) error {
|
func (xmlBinding) Bind(req *http.Request, obj any, opts ...Option) error {
|
||||||
return decodeXML(req.Body, obj)
|
return decodeXML(req.Body, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ func (yamlBinding) Name() string {
|
|||||||
return "yaml"
|
return "yaml"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (yamlBinding) Bind(req *http.Request, obj any) error {
|
func (yamlBinding) Bind(req *http.Request, obj any, opts ...Option) error {
|
||||||
return decodeYAML(req.Body, obj)
|
return decodeYAML(req.Body, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
context.go
15
context.go
@ -732,7 +732,20 @@ func (c *Context) ShouldBindUri(obj any) error {
|
|||||||
// ShouldBindWith binds the passed struct pointer using the specified binding engine.
|
// ShouldBindWith binds the passed struct pointer using the specified binding engine.
|
||||||
// See the binding package.
|
// See the binding package.
|
||||||
func (c *Context) ShouldBindWith(obj any, b binding.Binding) error {
|
func (c *Context) ShouldBindWith(obj any, b binding.Binding) error {
|
||||||
return b.Bind(c.Request, obj)
|
return b.Bind(c.Request, obj, binding.WithParams(func() (ret map[string]interface{}) {
|
||||||
|
ret = make(map[string]interface{})
|
||||||
|
for _, item := range c.Params {
|
||||||
|
ret[item.Key] = item.Value
|
||||||
|
}
|
||||||
|
for key, val := range c.Request.URL.Query() {
|
||||||
|
if len(val) == 1 {
|
||||||
|
ret[key] = val[0]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ret[key] = val
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShouldBindBodyWith is similar with ShouldBindWith, but it stores the request
|
// ShouldBindBodyWith is similar with ShouldBindWith, but it stores the request
|
||||||
|
4
mode.go
4
mode.go
@ -94,6 +94,10 @@ func EnableJsonDecoderDisallowUnknownFields() {
|
|||||||
binding.EnableDecoderDisallowUnknownFields = true
|
binding.EnableDecoderDisallowUnknownFields = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EnableParamsAndQueryBinding() {
|
||||||
|
binding.EnableParamsAndQueryBinding = true
|
||||||
|
}
|
||||||
|
|
||||||
// Mode returns current gin mode.
|
// Mode returns current gin mode.
|
||||||
func Mode() string {
|
func Mode() string {
|
||||||
return modeName
|
return modeName
|
||||||
|
Loading…
x
Reference in New Issue
Block a user