Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Protobuf format response and unit test #1479

Merged
merged 25 commits into from
Aug 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5682f53
Add support for Protobuf format response
salamer Aug 12, 2018
42dd325
add TestRenderProtoBuf
salamer Aug 12, 2018
11e1ba3
add protobuf render test
salamer Aug 18, 2018
1aa0e18
chore: add return or remove else for reduce indent (#1470)
thinkerou Aug 12, 2018
7d89b71
improve utils code coverage (#1473)
thinkerou Aug 12, 2018
df04038
improve render code coverage (#1474)
thinkerou Aug 12, 2018
a712509
unify test data (#1417)
thinkerou Aug 12, 2018
9ce5f61
docs: remove double negative in README.md (#1480)
awulkan Aug 12, 2018
85d33ff
chore: use http.Status* instead of hard code (#1482)
thinkerou Aug 14, 2018
06d50f1
add issue and pull request template explain (#1483)
thinkerou Aug 14, 2018
a190c8b
docs: add changelog for v1.3.0, update authors and version const (#1478)
javierprovecho Aug 14, 2018
95fdb35
Fix typo in readme (#1490)
houjunchen Aug 15, 2018
3cce9fb
chore: upgrade dependency library version (#1491)
thinkerou Aug 16, 2018
4e28f1e
Add BindXML AND ShouldBindXML #1484 (#1485)
syssam Aug 17, 2018
64ecab2
Set default time format in form binding (#1487)
lokhman Aug 17, 2018
b62f951
readme: fix users link (#1493)
easonlin404 Aug 17, 2018
6af1a17
Fix typo in README [ci skip] (#1492)
crispgm Aug 17, 2018
65a97e1
Update readme about the version of gin (#1494)
chainhelen Aug 17, 2018
b6cb77e
add full protobuf rendering test
salamer Aug 18, 2018
86fe335
fixed typo
salamer Aug 18, 2018
8ba804b
fixed missed code
salamer Aug 18, 2018
75aa0c0
filled test
salamer Aug 18, 2018
5be19bd
update annotation of protobuf
salamer Aug 18, 2018
e51d726
add some protobuf rendering examples in README, add some tests and up…
salamer Aug 18, 2018
47a973a
update the README code annotations, make it more clear
salamer Aug 18, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi
- [Bind Query String or Post Data](#bind-query-string-or-post-data)
- [Bind HTML checkboxes](#bind-html-checkboxes)
- [Multipart/Urlencoded binding](#multiparturlencoded-binding)
- [XML, JSON and YAML rendering](#xml-json-and-yaml-rendering)
- [XML, JSON, YAML and ProtoBuf rendering](#xml-json-yaml-and-protobuf-rendering)
- [JSONP rendering](#jsonp)
- [Serving static files](#serving-static-files)
- [Serving data from reader](#serving-data-from-reader)
Expand Down Expand Up @@ -871,7 +871,7 @@ Test it with:
$ curl -v --form user=user --form password=password http://localhost:8080/login
```

### XML, JSON and YAML rendering
### XML, JSON, YAML and ProtoBuf rendering

```go
func main() {
Expand Down Expand Up @@ -905,6 +905,19 @@ func main() {
c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
})

r.GET("/someProtoBuf", func(c *gin.Context) {
reps := []int64{int64(1), int64(2)}
label := "test"
// The specific definition of protobuf is written in the testdata/protoexample file.
data := &protoexample.Test{
Label: &label,
Reps: reps,
}
// Note that data becomes binary data in the response
// Will output protoexample.Test protobuf serialized data
c.ProtoBuf(http.StatusOK, data)
})

// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
Expand Down
6 changes: 6 additions & 0 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/gin-contrib/sse"
"github.com/gin-gonic/gin/binding"
"github.com/gin-gonic/gin/render"
"github.com/golang/protobuf/proto"
)

// Content-Type MIME of the most common data formats.
Expand Down Expand Up @@ -845,6 +846,11 @@ func (c *Context) Stream(step func(w io.Writer) bool) {
}
}

// ProtoBuf serializes the given struct as ProtoBuf into the response body.
func (c *Context) ProtoBuf(code int, obj proto.Message) {
c.Render(code, render.ProtoBuf{Data: obj})
}

/************************************/
/******** CONTENT NEGOTIATION *******/
/************************************/
Expand Down
27 changes: 27 additions & 0 deletions context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ import (

"github.com/gin-contrib/sse"
"github.com/gin-gonic/gin/binding"
"github.com/golang/protobuf/proto"
"github.com/stretchr/testify/assert"
"golang.org/x/net/context"

testdata "github.com/gin-gonic/gin/testdata/protoexample"
)

var _ context.Context = &Context{}
Expand Down Expand Up @@ -954,6 +957,30 @@ func TestContextRenderYAML(t *testing.T) {
assert.Equal(t, "application/x-yaml; charset=utf-8", w.HeaderMap.Get("Content-Type"))
}

// TestContextRenderProtoBuf tests that the response is serialized as ProtoBuf
// and Content-Type is set to application/x-protobuf
// and we just use the example protobuf to check if the response is correct
func TestContextRenderProtoBuf(t *testing.T) {
w := httptest.NewRecorder()
c, _ := CreateTestContext(w)

reps := []int64{int64(1), int64(2)}
label := "test"
data := &testdata.Test{
Label: &label,
Reps: reps,
}

c.ProtoBuf(http.StatusCreated, data)

protoData, err := proto.Marshal(data)
assert.NoError(t, err)

assert.Equal(t, http.StatusCreated, w.Code)
assert.Equal(t, string(protoData[:]), w.Body.String())
assert.Equal(t, "application/x-protobuf", w.HeaderMap.Get("Content-Type"))
}

func TestContextHeaders(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
c.Header("Content-Type", "text/plain")
Expand Down
33 changes: 33 additions & 0 deletions render/protobuf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2018 Gin Core Team. 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/golang/protobuf/proto"
)

type ProtoBuf struct {
Data proto.Message
}

var protobufContentType = []string{"application/x-protobuf"}

func (r ProtoBuf) Render(w http.ResponseWriter) error {
r.WriteContentType(w)

bytes, err := proto.Marshal(r.Data)
if err != nil {
return err
}

w.Write(bytes)
return nil
}

func (r ProtoBuf) WriteContentType(w http.ResponseWriter) {
writeContentType(w, protobufContentType)
}
1 change: 1 addition & 0 deletions render/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var (
_ Render = MsgPack{}
_ Render = Reader{}
_ Render = AsciiJSON{}
_ Render = ProtoBuf{}
)

func writeContentType(w http.ResponseWriter, value []string) {
Expand Down
31 changes: 31 additions & 0 deletions render/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"strings"
"testing"

testdata "github.com/gin-gonic/gin/testdata/protoexample"
"github.com/golang/protobuf/proto"
"github.com/stretchr/testify/assert"
"github.com/ugorji/go/codec"
)
Expand Down Expand Up @@ -265,6 +267,35 @@ func TestRenderYAMLFail(t *testing.T) {
assert.Error(t, err)
}

// test Protobuf rendering
func TestRenderProtoBuf(t *testing.T) {
w := httptest.NewRecorder()
reps := []int64{int64(1), int64(2)}
label := "test"
data := &testdata.Test{
Label: &label,
Reps: reps,
}

(ProtoBuf{data}).WriteContentType(w)
protoData, err := proto.Marshal(data)
assert.NoError(t, err)
assert.Equal(t, "application/x-protobuf", w.Header().Get("Content-Type"))

err = (ProtoBuf{data}).Render(w)

assert.NoError(t, err)
assert.Equal(t, string(protoData[:]), w.Body.String())
assert.Equal(t, "application/x-protobuf", w.Header().Get("Content-Type"))
}

func TestRenderProtoBufFail(t *testing.T) {
w := httptest.NewRecorder()
data := &testdata.Test{}
err := (ProtoBuf{data}).Render(w)
assert.Error(t, err)
}

func TestRenderXML(t *testing.T) {
w := httptest.NewRecorder()
data := xmlmap{
Expand Down