Skip to content

Commit

Permalink
binding/render: modular deps
Browse files Browse the repository at this point in the history
  • Loading branch information
sapk committed Apr 17, 2019
1 parent ffcbe77 commit 4f66657
Show file tree
Hide file tree
Showing 35 changed files with 657 additions and 359 deletions.
126 changes: 43 additions & 83 deletions binding/binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,110 +4,70 @@

package binding

import "net/http"
import (
"fmt"

// Content-Type MIME of the most common data formats.
const (
MIMEJSON = "application/json"
MIMEHTML = "text/html"
MIMEXML = "application/xml"
MIMEXML2 = "text/xml"
MIMEPlain = "text/plain"
MIMEPOSTForm = "application/x-www-form-urlencoded"
MIMEMultipartPOSTForm = "multipart/form-data"
MIMEPROTOBUF = "application/x-protobuf"
MIMEMSGPACK = "application/x-msgpack"
MIMEMSGPACK2 = "application/msgpack"
MIMEYAML = "application/x-yaml"
"github.com/gin-gonic/gin/binding/common"
)

// 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
}

// BindingBody adds BindBody method to Binding. BindBody is similar with Bind,
// but it reads the body from supplied bytes instead of req.Body.
type BindingBody interface {
Binding
BindBody([]byte, interface{}) error
}

// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
// but it read the Params.
type BindingUri interface {
Name() string
BindUri(map[string][]string, 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 request. 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.
// If the received type is a struct or pointer to a struct, the validation should be performed.
// If the struct is not valid or the validation itself fails, a descriptive error should be returned.
// Otherwise nil must be returned.
ValidateStruct(interface{}) 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{}
Form = formBinding{}
Query = queryBinding{}
FormPost = formPostBinding{}
FormMultipart = formMultipartBinding{}
ProtoBuf = protobufBinding{}
MsgPack = msgpackBinding{}
YAML = yamlBinding{}
Uri = uriBinding{}
FormMultipart = formMultipartBinding{}
)

// Default returns the appropriate Binding instance based on the HTTP method
// and the content type.
func Default(method, contentType string) Binding {
func Default(method, contentType string) common.Binding {
if method == "GET" {
return Form
}

switch contentType {
case MIMEJSON:
return JSON
case MIMEXML, MIMEXML2:
return XML
case MIMEPROTOBUF:
return ProtoBuf
case MIMEMSGPACK, MIMEMSGPACK2:
return MsgPack
case MIMEYAML:
return YAML
case MIMEMultipartPOSTForm:
case common.MIMEMultipartPOSTForm:
return FormMultipart
default: // case MIMEPOSTForm:
return Form
default:
b, ok := common.List[contentType]
if !ok {
return Form //Default to Form
}
return b
}
}

func validate(obj interface{}) error {
if Validator == nil {
return nil
//YAML return the binding for yaml if loaded
func YAML() common.BindingBody {
return retBinding(common.MIMEYAML)
}

//JSON return the binding for json if loaded
func JSON() common.BindingBody {
return retBinding(common.MIMEJSON)
}

//XML return the binding for xml if loaded
func XML() common.BindingBody {
return retBinding(common.MIMEXML)
}

//ProtoBuf return the binding for ProtoBuf if loaded
func ProtoBuf() common.BindingBody {
return retBinding(common.MIMEPROTOBUF)
}

//MsgPack return the binding for MsgPack if loaded
func MsgPack() common.BindingBody {
return retBinding(common.MIMEMSGPACK)
}

//retBinding Search for a render and panic on not found
func retBinding(contentType string) common.BindingBody {
b, ok := common.List[contentType]
if !ok {
panic(fmt.Sprintf("Undefined binding %s", contentType))
}
return Validator.ValidateStruct(obj)
return b
}
13 changes: 7 additions & 6 deletions binding/binding_body_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io/ioutil"
"testing"

"github.com/gin-gonic/gin/binding/common"
"github.com/gin-gonic/gin/testdata/protoexample"
"github.com/golang/protobuf/proto"
"github.com/stretchr/testify/assert"
Expand All @@ -14,31 +15,31 @@ import (
func TestBindingBody(t *testing.T) {
for _, tt := range []struct {
name string
binding BindingBody
binding common.BindingBody
body string
want string
}{
{
name: "JSON binding",
binding: JSON,
binding: JSON(),
body: `{"foo":"FOO"}`,
},
{
name: "XML binding",
binding: XML,
binding: XML(),
body: `<?xml version="1.0" encoding="UTF-8"?>
<root>
<foo>FOO</foo>
</root>`,
},
{
name: "MsgPack binding",
binding: MsgPack,
binding: MsgPack(),
body: msgPackBody(t),
},
{
name: "YAML binding",
binding: YAML,
binding: YAML(),
body: `foo: FOO`,
},
} {
Expand Down Expand Up @@ -67,6 +68,6 @@ func TestBindingBodyProto(t *testing.T) {
req := requestWithBody("POST", "/", string(data))
form := protoexample.Test{}
body, _ := ioutil.ReadAll(req.Body)
assert.NoError(t, ProtoBuf.BindBody(body, &form))
assert.NoError(t, ProtoBuf().BindBody(body, &form))
assert.Equal(t, test, form)
}
Loading

0 comments on commit 4f66657

Please sign in to comment.