Added support for MessagePack binding and rendering (#808)
Added deps to vendor.json and fixed rendering bug
This commit is contained in:
		| @ -15,6 +15,8 @@ const ( | ||||
| 	MIMEPOSTForm          = "application/x-www-form-urlencoded" | ||||
| 	MIMEMultipartPOSTForm = "multipart/form-data" | ||||
| 	MIMEPROTOBUF          = "application/x-protobuf" | ||||
| 	MIMEMSGPACK           = "application/x-msgpack" | ||||
| 	MIMEMSGPACK2          = "application/msgpack" | ||||
| ) | ||||
|  | ||||
| type Binding interface { | ||||
| @ -40,6 +42,7 @@ var ( | ||||
| 	FormPost      = formPostBinding{} | ||||
| 	FormMultipart = formMultipartBinding{} | ||||
| 	ProtoBuf      = protobufBinding{} | ||||
| 	MsgPack       = msgpackBinding{} | ||||
| ) | ||||
|  | ||||
| func Default(method, contentType string) Binding { | ||||
| @ -53,6 +56,8 @@ func Default(method, contentType string) Binding { | ||||
| 			return XML | ||||
| 		case MIMEPROTOBUF: | ||||
| 			return ProtoBuf | ||||
| 		case MIMEMSGPACK, MIMEMSGPACK2: | ||||
| 			return MsgPack | ||||
| 		default: //case MIMEPOSTForm, MIMEMultipartPOSTForm: | ||||
| 			return Form | ||||
| 		} | ||||
|  | ||||
| @ -12,17 +12,18 @@ import ( | ||||
|  | ||||
| 	"github.com/gin-gonic/gin/binding/example" | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| 	"github.com/ugorji/go/codec" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| type FooStruct struct { | ||||
| 	Foo string `json:"foo" form:"foo" xml:"foo" binding:"required"` | ||||
| 	Foo string `msgpack:"foo" json:"foo" form:"foo" xml:"foo" binding:"required"` | ||||
| } | ||||
|  | ||||
| type FooBarStruct struct { | ||||
| 	FooStruct | ||||
| 	Bar string `json:"bar" form:"bar" xml:"bar" binding:"required"` | ||||
| 	Bar string `msgpack:"bar" json:"bar" form:"bar" xml:"bar" binding:"required"` | ||||
| } | ||||
|  | ||||
| func TestBindingDefault(t *testing.T) { | ||||
| @ -43,6 +44,9 @@ func TestBindingDefault(t *testing.T) { | ||||
|  | ||||
| 	assert.Equal(t, Default("POST", MIMEPROTOBUF), ProtoBuf) | ||||
| 	assert.Equal(t, Default("PUT", MIMEPROTOBUF), ProtoBuf) | ||||
|  | ||||
| 	assert.Equal(t, Default("POST", MIMEMSGPACK), MsgPack) | ||||
| 	assert.Equal(t, Default("PUT", MIMEMSGPACK2), MsgPack) | ||||
| } | ||||
|  | ||||
| func TestBindingJSON(t *testing.T) { | ||||
| @ -121,6 +125,26 @@ func TestBindingProtoBuf(t *testing.T) { | ||||
| 		string(data), string(data[1:])) | ||||
| } | ||||
|  | ||||
| func TestBindingMsgPack(t *testing.T) { | ||||
| 	test := FooStruct{ | ||||
| 		Foo: "bar", | ||||
| 	} | ||||
|  | ||||
| 	h := new(codec.MsgpackHandle) | ||||
| 	assert.NotNil(t, h) | ||||
| 	buf := bytes.NewBuffer([]byte{}) | ||||
| 	assert.NotNil(t, buf) | ||||
| 	err := codec.NewEncoder(buf, h).Encode(test) | ||||
| 	assert.NoError(t, err) | ||||
|  | ||||
| 	data := buf.Bytes() | ||||
|  | ||||
| 	testMsgPackBodyBinding(t, | ||||
| 		MsgPack, "msgpack", | ||||
| 		"/", "/", | ||||
| 		string(data), string(data[1:])) | ||||
| } | ||||
|  | ||||
| func TestValidationFails(t *testing.T) { | ||||
| 	var obj FooStruct | ||||
| 	req := requestWithBody("POST", "/", `{"bar": "foo"}`) | ||||
| @ -213,6 +237,23 @@ func testProtoBodyBinding(t *testing.T, b Binding, name, path, badPath, body, ba | ||||
| 	assert.Error(t, err) | ||||
| } | ||||
|  | ||||
| func testMsgPackBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) { | ||||
| 	assert.Equal(t, b.Name(), name) | ||||
|  | ||||
| 	obj := FooStruct{} | ||||
| 	req := requestWithBody("POST", path, body) | ||||
| 	req.Header.Add("Content-Type", MIMEMSGPACK) | ||||
| 	err := b.Bind(req, &obj) | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, obj.Foo, "bar") | ||||
|  | ||||
| 	obj = FooStruct{} | ||||
| 	req = requestWithBody("POST", badPath, badBody) | ||||
| 	req.Header.Add("Content-Type", MIMEMSGPACK) | ||||
| 	err = MsgPack.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 | ||||
|  | ||||
							
								
								
									
										28
									
								
								binding/msgpack.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								binding/msgpack.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| // Copyright 2017 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 ( | ||||
| 	"net/http" | ||||
|  | ||||
| 	"github.com/ugorji/go/codec" | ||||
| ) | ||||
|  | ||||
| type msgpackBinding struct{} | ||||
|  | ||||
| func (msgpackBinding) Name() string { | ||||
| 	return "msgpack" | ||||
| } | ||||
|  | ||||
| func (msgpackBinding) Bind(req *http.Request, obj interface{}) error { | ||||
|  | ||||
| 	if err := codec.NewDecoder(req.Body, new(codec.MsgpackHandle)).Decode(&obj); err != nil { | ||||
| 		//var decoder *codec.Decoder = codec.NewDecoder(req.Body, &codec.MsgpackHandle) | ||||
| 		//if err := decoder.Decode(&obj); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return validate(obj) | ||||
|  | ||||
| } | ||||
							
								
								
									
										31
									
								
								render/msgpack.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								render/msgpack.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| // Copyright 2017 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 render | ||||
|  | ||||
| import ( | ||||
| 	"net/http" | ||||
|  | ||||
| 	"github.com/ugorji/go/codec" | ||||
| ) | ||||
|  | ||||
| type MsgPack struct { | ||||
| 	Data interface{} | ||||
| } | ||||
|  | ||||
| var msgpackContentType = []string{"application/msgpack; charset=utf-8"} | ||||
|  | ||||
| func (r MsgPack) WriteContentType(w http.ResponseWriter) { | ||||
| 	writeContentType(w, msgpackContentType) | ||||
| } | ||||
|  | ||||
| func (r MsgPack) Render(w http.ResponseWriter) error { | ||||
| 	return WriteMsgPack(w, r.Data) | ||||
| } | ||||
|  | ||||
| func WriteMsgPack(w http.ResponseWriter, obj interface{}) error { | ||||
| 	writeContentType(w, msgpackContentType) | ||||
| 	var h codec.Handle = new(codec.MsgpackHandle) | ||||
| 	return codec.NewEncoder(w, h).Encode(obj) | ||||
| } | ||||
| @ -22,6 +22,8 @@ var ( | ||||
| 	_ HTMLRender = HTMLDebug{} | ||||
| 	_ HTMLRender = HTMLProduction{} | ||||
| 	_ Render     = YAML{} | ||||
| 	_ Render     = MsgPack{} | ||||
| 	_ Render     = MsgPack{} | ||||
| ) | ||||
|  | ||||
| func writeContentType(w http.ResponseWriter, value []string) { | ||||
|  | ||||
| @ -5,17 +5,40 @@ | ||||
| package render | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/xml" | ||||
| 	"html/template" | ||||
| 	"net/http/httptest" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"github.com/ugorji/go/codec" | ||||
| ) | ||||
|  | ||||
| // TODO unit tests | ||||
| // test errors | ||||
|  | ||||
| func TestRenderMsgPack(t *testing.T) { | ||||
| 	w := httptest.NewRecorder() | ||||
| 	data := map[string]interface{}{ | ||||
| 		"foo": "bar", | ||||
| 	} | ||||
|  | ||||
| 	err := (MsgPack{data}).Render(w) | ||||
|  | ||||
| 	assert.NoError(t, err) | ||||
|  | ||||
| 	h := new(codec.MsgpackHandle) | ||||
| 	assert.NotNil(t, h) | ||||
| 	buf := bytes.NewBuffer([]byte{}) | ||||
| 	assert.NotNil(t, buf) | ||||
| 	err = codec.NewEncoder(buf, h).Encode(data) | ||||
|  | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, w.Body.String(), string(buf.Bytes())) | ||||
| 	assert.Equal(t, w.Header().Get("Content-Type"), "application/msgpack; charset=utf-8") | ||||
| } | ||||
|  | ||||
| func TestRenderJSON(t *testing.T) { | ||||
| 	w := httptest.NewRecorder() | ||||
| 	data := map[string]interface{}{ | ||||
|  | ||||
							
								
								
									
										6
									
								
								vendor/vendor.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/vendor.json
									
									
									
									
										vendored
									
									
								
							| @ -47,6 +47,12 @@ | ||||
| 			"revision": "976c720a22c8eb4eb6a0b4348ad85ad12491a506", | ||||
| 			"revisionTime": "2016-09-25T22:06:09Z" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"checksumSHA1": "CoxdaTYdPZNJXr8mJfLxye428N0=", | ||||
| 			"path": "github.com/ugorji/go/codec", | ||||
| 			"revision": "c88ee250d0221a57af388746f5cf03768c21d6e2", | ||||
| 			"revisionTime": "2017-02-15T20:11:44Z" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"checksumSHA1": "9jjO5GjLa0XF/nfWihF02RoH4qc=", | ||||
| 			"comment": "release-branch.go1.7", | ||||
|  | ||||
		Reference in New Issue
	
	Block a user