Merge branch 'zhing-new-binding-validator' into develop
This commit is contained in:
		@ -14,6 +14,7 @@ const (
 | 
			
		||||
	MIMEPlain             = "text/plain"
 | 
			
		||||
	MIMEPOSTForm          = "application/x-www-form-urlencoded"
 | 
			
		||||
	MIMEMultipartPOSTForm = "multipart/form-data"
 | 
			
		||||
	MIMEPROTOBUF          = "application/x-protobuf"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Binding interface {
 | 
			
		||||
@ -38,6 +39,7 @@ var (
 | 
			
		||||
	Form          = formBinding{}
 | 
			
		||||
	FormPost      = formPostBinding{}
 | 
			
		||||
	FormMultipart = formMultipartBinding{}
 | 
			
		||||
	ProtoBuf      = protobufBinding{}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Default(method, contentType string) Binding {
 | 
			
		||||
@ -49,6 +51,8 @@ func Default(method, contentType string) Binding {
 | 
			
		||||
			return JSON
 | 
			
		||||
		case MIMEXML, MIMEXML2:
 | 
			
		||||
			return XML
 | 
			
		||||
		case MIMEPROTOBUF:
 | 
			
		||||
			return ProtoBuf
 | 
			
		||||
		default: //case MIMEPOSTForm, MIMEMultipartPOSTForm:
 | 
			
		||||
			return Form
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,9 @@ import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/gin-gonic/gin/binding/example"
 | 
			
		||||
	"github.com/golang/protobuf/proto"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@ -37,6 +40,9 @@ func TestBindingDefault(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	assert.Equal(t, Default("POST", MIMEMultipartPOSTForm), Form)
 | 
			
		||||
	assert.Equal(t, Default("PUT", MIMEMultipartPOSTForm), Form)
 | 
			
		||||
 | 
			
		||||
	assert.Equal(t, Default("POST", MIMEPROTOBUF), ProtoBuf)
 | 
			
		||||
	assert.Equal(t, Default("PUT", MIMEPROTOBUF), ProtoBuf)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestBindingJSON(t *testing.T) {
 | 
			
		||||
@ -103,6 +109,18 @@ func TestBindingFormMultipart(t *testing.T) {
 | 
			
		||||
	assert.Equal(t, obj.Bar, "foo")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestBindingProtoBuf(t *testing.T) {
 | 
			
		||||
	test := &example.Test{
 | 
			
		||||
		Label: proto.String("yes"),
 | 
			
		||||
	}
 | 
			
		||||
	data, _ := proto.Marshal(test)
 | 
			
		||||
 | 
			
		||||
	testProtoBodyBinding(t,
 | 
			
		||||
		ProtoBuf, "protobuf",
 | 
			
		||||
		"/", "/",
 | 
			
		||||
		string(data), string(data[1:]))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestValidationFails(t *testing.T) {
 | 
			
		||||
	var obj FooStruct
 | 
			
		||||
	req := requestWithBody("POST", "/", `{"bar": "foo"}`)
 | 
			
		||||
@ -156,6 +174,23 @@ func testBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testProtoBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
 | 
			
		||||
	assert.Equal(t, b.Name(), name)
 | 
			
		||||
 | 
			
		||||
	obj := example.Test{}
 | 
			
		||||
	req := requestWithBody("POST", path, body)
 | 
			
		||||
	req.Header.Add("Content-Type", MIMEPROTOBUF)
 | 
			
		||||
	err := b.Bind(req, &obj)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, *obj.Label, "yes")
 | 
			
		||||
 | 
			
		||||
	obj = example.Test{}
 | 
			
		||||
	req = requestWithBody("POST", badPath, badBody)
 | 
			
		||||
	req.Header.Add("Content-Type", MIMEPROTOBUF)
 | 
			
		||||
	err = ProtoBuf.Bind(req, &obj)
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func requestWithBody(method, path, body string) (req *http.Request) {
 | 
			
		||||
	req, _ = http.NewRequest(method, path, bytes.NewBufferString(body))
 | 
			
		||||
	return
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										113
									
								
								binding/example/test.pb.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								binding/example/test.pb.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,113 @@
 | 
			
		||||
// Code generated by protoc-gen-go.
 | 
			
		||||
// source: test.proto
 | 
			
		||||
// DO NOT EDIT!
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Package example is a generated protocol buffer package.
 | 
			
		||||
 | 
			
		||||
It is generated from these files:
 | 
			
		||||
	test.proto
 | 
			
		||||
 | 
			
		||||
It has these top-level messages:
 | 
			
		||||
	Test
 | 
			
		||||
*/
 | 
			
		||||
package example
 | 
			
		||||
 | 
			
		||||
import proto "github.com/golang/protobuf/proto"
 | 
			
		||||
import math "math"
 | 
			
		||||
 | 
			
		||||
// Reference imports to suppress errors if they are not otherwise used.
 | 
			
		||||
var _ = proto.Marshal
 | 
			
		||||
var _ = math.Inf
 | 
			
		||||
 | 
			
		||||
type FOO int32
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	FOO_X FOO = 17
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var FOO_name = map[int32]string{
 | 
			
		||||
	17: "X",
 | 
			
		||||
}
 | 
			
		||||
var FOO_value = map[string]int32{
 | 
			
		||||
	"X": 17,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x FOO) Enum() *FOO {
 | 
			
		||||
	p := new(FOO)
 | 
			
		||||
	*p = x
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
func (x FOO) String() string {
 | 
			
		||||
	return proto.EnumName(FOO_name, int32(x))
 | 
			
		||||
}
 | 
			
		||||
func (x *FOO) UnmarshalJSON(data []byte) error {
 | 
			
		||||
	value, err := proto.UnmarshalJSONEnum(FOO_value, data, "FOO")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	*x = FOO(value)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Test struct {
 | 
			
		||||
	Label            *string             `protobuf:"bytes,1,req,name=label" json:"label,omitempty"`
 | 
			
		||||
	Type             *int32              `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"`
 | 
			
		||||
	Reps             []int64             `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"`
 | 
			
		||||
	Optionalgroup    *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"`
 | 
			
		||||
	XXX_unrecognized []byte              `json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Test) Reset()         { *m = Test{} }
 | 
			
		||||
func (m *Test) String() string { return proto.CompactTextString(m) }
 | 
			
		||||
func (*Test) ProtoMessage()    {}
 | 
			
		||||
 | 
			
		||||
const Default_Test_Type int32 = 77
 | 
			
		||||
 | 
			
		||||
func (m *Test) GetLabel() string {
 | 
			
		||||
	if m != nil && m.Label != nil {
 | 
			
		||||
		return *m.Label
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Test) GetType() int32 {
 | 
			
		||||
	if m != nil && m.Type != nil {
 | 
			
		||||
		return *m.Type
 | 
			
		||||
	}
 | 
			
		||||
	return Default_Test_Type
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Test) GetReps() []int64 {
 | 
			
		||||
	if m != nil {
 | 
			
		||||
		return m.Reps
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Test) GetOptionalgroup() *Test_OptionalGroup {
 | 
			
		||||
	if m != nil {
 | 
			
		||||
		return m.Optionalgroup
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Test_OptionalGroup struct {
 | 
			
		||||
	RequiredField    *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"`
 | 
			
		||||
	XXX_unrecognized []byte  `json:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Test_OptionalGroup) Reset()         { *m = Test_OptionalGroup{} }
 | 
			
		||||
func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) }
 | 
			
		||||
func (*Test_OptionalGroup) ProtoMessage()    {}
 | 
			
		||||
 | 
			
		||||
func (m *Test_OptionalGroup) GetRequiredField() string {
 | 
			
		||||
	if m != nil && m.RequiredField != nil {
 | 
			
		||||
		return *m.RequiredField
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	proto.RegisterEnum("example.FOO", FOO_name, FOO_value)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								binding/example/test.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								binding/example/test.proto
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
package example;
 | 
			
		||||
 | 
			
		||||
enum FOO {X=17;};
 | 
			
		||||
 | 
			
		||||
message Test {
 | 
			
		||||
   required string label = 1;
 | 
			
		||||
   optional int32 type = 2[default=77];
 | 
			
		||||
   repeated int64 reps = 3;
 | 
			
		||||
   optional group OptionalGroup = 4{
 | 
			
		||||
     required string RequiredField = 5;
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								binding/protobuf.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								binding/protobuf.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
			
		||||
// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package binding
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/golang/protobuf/proto"
 | 
			
		||||
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type protobufBinding struct{}
 | 
			
		||||
 | 
			
		||||
func (_ protobufBinding) Name() string {
 | 
			
		||||
	return "protobuf"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (_ protobufBinding) Bind(req *http.Request, obj interface{}) error {
 | 
			
		||||
 | 
			
		||||
	buf, err := ioutil.ReadAll(req.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = proto.Unmarshal(buf, obj.(proto.Message)); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//Here it's same to return validate(obj), but util now we cann't add `binding:""` to the struct
 | 
			
		||||
	//which automatically generate by gen-proto
 | 
			
		||||
	return nil
 | 
			
		||||
	//return validate(obj)
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user