From 5682f53f386312e5b1413996ec2b8fc5aa6e5d34 Mon Sep 17 00:00:00 2001 From: salamer Date: Sun, 12 Aug 2018 14:46:43 +0800 Subject: [PATCH 1/2] Add support for Protobuf format response --- context.go | 6 ++++++ render/protobuf.go | 33 +++++++++++++++++++++++++++++++++ render/render.go | 1 + 3 files changed, 40 insertions(+) create mode 100644 render/protobuf.go diff --git a/context.go b/context.go index 724ded79..c73748eb 100644 --- a/context.go +++ b/context.go @@ -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. @@ -835,6 +836,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 *******/ /************************************/ diff --git a/render/protobuf.go b/render/protobuf.go new file mode 100644 index 00000000..eb34619c --- /dev/null +++ b/render/protobuf.go @@ -0,0 +1,33 @@ +// 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/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) +} diff --git a/render/render.go b/render/render.go index 4ff1c7b6..df0d1d7c 100755 --- a/render/render.go +++ b/render/render.go @@ -27,6 +27,7 @@ var ( _ Render = MsgPack{} _ Render = Reader{} _ Render = AsciiJSON{} + _ Render = ProtoBuf{} ) func writeContentType(w http.ResponseWriter, value []string) { From 73b20fdb2aaa35d36347d377accc1a4a637633d8 Mon Sep 17 00:00:00 2001 From: salamer Date: Sun, 12 Aug 2018 15:32:35 +0800 Subject: [PATCH 2/2] add RenderProtoBuf test --- context_test.go | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/context_test.go b/context_test.go index 0185507f..a8cb4d10 100644 --- a/context_test.go +++ b/context_test.go @@ -17,11 +17,14 @@ import ( "testing" "time" + "io" + "github.com/gin-contrib/sse" "github.com/gin-gonic/gin/binding" + pb "github.com/gin-gonic/gin/examples/grpc/pb" + "github.com/golang/protobuf/proto" "github.com/stretchr/testify/assert" "golang.org/x/net/context" - "io" ) var _ context.Context = &Context{} @@ -953,6 +956,23 @@ 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 YAML +// 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) + + c.ProtoBuf(201, &pb.HelloRequest{Name: "Hello"}) + + realProtoBuf, err := proto.Marshal(&pb.HelloRequest{Name: "Hello"}) + assert.Nil(t, err) + + assert.Equal(t, 201, w.Code) + assert.Equal(t, realProtoBuf, w.Body.Bytes()) + 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")