Merge branch 'new-binding-validator' of https://github.com/zhing/gin into zhing-new-binding-validator
Conflicts: binding/binding.go binding/binding_test.go
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