Skip to content

Commit

Permalink
Added support for MessagePack binding and rendering
Browse files Browse the repository at this point in the history
Added deps to vendor.json and fixed rendering bug

Fixed vendoring bug
  • Loading branch information
Harindu Perera committed Feb 17, 2017
1 parent 8632480 commit 2f20804
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 2 deletions.
5 changes: 5 additions & 0 deletions binding/binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -40,6 +42,7 @@ var (
FormPost = formPostBinding{}
FormMultipart = formMultipartBinding{}
ProtoBuf = protobufBinding{}
MsgPack = msgpackBinding{}
)

func Default(method, contentType string) Binding {
Expand All @@ -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
}
Expand Down
45 changes: 43 additions & 2 deletions binding/binding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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"}`)
Expand Down Expand Up @@ -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
Expand Down
28 changes: 28 additions & 0 deletions binding/msgpack.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// 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/ugorji/go/codec"

"net/http"
)

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 changes: 31 additions & 0 deletions render/msgpack.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 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 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)
}
2 changes: 2 additions & 0 deletions render/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ var (
_ HTMLRender = HTMLDebug{}
_ HTMLRender = HTMLProduction{}
_ Render = YAML{}
_ Render = MsgPack{}
_ Render = MsgPack{}
)

func writeContentType(w http.ResponseWriter, value []string) {
Expand Down
23 changes: 23 additions & 0 deletions render/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{}{
Expand Down
6 changes: 6 additions & 0 deletions vendor/vendor.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit 2f20804

Please sign in to comment.