Browse Source

Merge branch 'new-binding-validator' of https://github.com/zhing/gin into zhing-new-binding-validator

Conflicts:
	binding/binding.go
	binding/binding_test.go
Javier Provecho Fernandez 10 years ago
parent
commit
e5339a3f4d
5 changed files with 199 additions and 0 deletions
  1. 4 0
      binding/binding.go
  2. 35 0
      binding/binding_test.go
  3. 113 0
      binding/example/test.pb.go
  4. 12 0
      binding/example/test.proto
  5. 35 0
      binding/protobuf.go

+ 4 - 0
binding/binding.go

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

+ 35 - 0
binding/binding_test.go

@@ -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 - 0
binding/example/test.pb.go

@@ -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 - 0
binding/example/test.proto

@@ -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 - 0
binding/protobuf.go

@@ -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)
+}