Skip to content

Commit

Permalink
feat: yaml binding (#96)
Browse files Browse the repository at this point in the history
  • Loading branch information
fsamin authored Aug 4, 2023
1 parent 30eb770 commit 46f3c8e
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 2 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (
github.com/pires/go-proxyproto v0.6.0
github.com/poy/onpar v1.1.2 // indirect
github.com/ziutek/mymysql v1.5.4 // indirect
sigs.k8s.io/yaml v1.3.0
)

go 1.13
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,5 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM=
launchpad.net/xmlpath v0.0.0-20130614043138-000000000004/go.mod h1:vqyExLOM3qBx7mvYRkoxjSCF945s0mbe7YynlKYXtsA=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
43 changes: 41 additions & 2 deletions tonic/tonic.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tonic

import (
"bytes"
"encoding"
"errors"
"fmt"
Expand All @@ -15,6 +16,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
validator "github.com/go-playground/validator/v10"
"sigs.k8s.io/yaml" // sigs.k8s.io/yaml is the alternative to the unmaintained lib github.com/ghodss/yaml. cf https://github.com/ghodss/yaml/issues/80
)

// DefaultMaxBodyBytes is the maximum allowed size of a request body in bytes.
Expand Down Expand Up @@ -96,8 +98,15 @@ func DefaultBindingHookMaxBodyBytes(maxBodyBytes int64) BindHook {
if c.Request.ContentLength == 0 || c.Request.Method == http.MethodGet {
return nil
}
if err := c.ShouldBindWith(i, binding.JSON); err != nil && err != io.EOF {
return fmt.Errorf("error parsing request body: %s", err.Error())
switch c.Request.Header.Get("Content-Type") {
case "text/x-yaml", "text/yaml", "text/yml", "application/x-yaml", "application/x-yml", "application/yaml", "application/yml":
if err := c.ShouldBindWith(i, yamlBinding{}); err != nil && err != io.EOF {
return fmt.Errorf("error parsing request body: %s", err.Error())
}
default:
if err := c.ShouldBindWith(i, binding.JSON); err != nil && err != io.EOF {
return fmt.Errorf("error parsing request body: %s", err.Error())
}
}
return nil
}
Expand Down Expand Up @@ -443,3 +452,33 @@ func bindStringValue(s string, v reflect.Value) error {
}
return nil
}

// yamlBinding is an implementation of gin's binding.Binding
// we don't use official gin's yamlBinding because we prefer to use github.com/ghodss/yaml
type yamlBinding struct{}

func (yamlBinding) Name() string {
return "yaml"
}

func (yamlBinding) Bind(req *http.Request, obj interface{}) error {
return decodeYAML(req.Body, obj)
}

func (yamlBinding) BindBody(body []byte, obj interface{}) error {
return decodeYAML(bytes.NewReader(body), obj)
}

func decodeYAML(r io.Reader, obj interface{}) error {
btes, err := io.ReadAll(r)
if err != nil {
return err
}
if err := yaml.Unmarshal(btes, &obj); err != nil {
return err
}
if binding.Validator == nil {
return nil
}
return binding.Validator.ValidateStruct(obj)
}

0 comments on commit 46f3c8e

Please sign in to comment.