add jsonpb Render

This commit is contained in:
hongshengjie 2022-03-02 13:55:31 +08:00
parent 3757142584
commit ffcd9bf771
3 changed files with 89 additions and 0 deletions

View File

@ -23,6 +23,8 @@ import (
"github.com/gin-contrib/sse" "github.com/gin-contrib/sse"
"github.com/gin-gonic/gin/binding" "github.com/gin-gonic/gin/binding"
"github.com/gin-gonic/gin/render" "github.com/gin-gonic/gin/render"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
) )
// Content-Type MIME of the most common data formats. // Content-Type MIME of the most common data formats.
@ -939,6 +941,12 @@ func (c *Context) JSON(code int, obj interface{}) {
c.Render(code, render.JSON{Data: obj}) c.Render(code, render.JSON{Data: obj})
} }
// JSONPB serializes the given proto Message as JSON into the response body.
// It also sets the Content-Type as "application/json".
func (c *Context) JSONPB(code int, obj proto.Message) {
c.Render(code, render.JSONPB{Data: obj, Option: protojson.MarshalOptions{EmitUnpopulated: true}})
}
// AsciiJSON serializes the given struct as JSON into the response body with unicode to ASCII string. // AsciiJSON serializes the given struct as JSON into the response body with unicode to ASCII string.
// It also sets the Content-Type as "application/json". // It also sets the Content-Type as "application/json".
func (c *Context) AsciiJSON(code int, obj interface{}) { func (c *Context) AsciiJSON(code int, obj interface{}) {

36
render/jsonpb.go Normal file
View File

@ -0,0 +1,36 @@
// 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 (
"encoding/json"
"net/http"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
)
// JSONPB contains the given proto.Message object.
type JSONPB struct {
Data proto.Message
datapb json.RawMessage
Option protojson.MarshalOptions
}
// Render (JSONPB) writes data with custom ContentType.
func (r JSONPB) Render(w http.ResponseWriter) (err error) {
r.datapb, err = r.Option.Marshal(r.Data)
if err != nil {
return err
}
writeContentType(w, jsonContentType)
_, err = w.Write(r.datapb)
return err
}
// WriteContentType (JSON) writes JSON ContentType.
func (r JSONPB) WriteContentType(w http.ResponseWriter) {
writeContentType(w, jsonContentType)
}

View File

@ -15,7 +15,9 @@ import (
"testing" "testing"
testdata "github.com/gin-gonic/gin/testdata/protoexample" testdata "github.com/gin-gonic/gin/testdata/protoexample"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
) )
@ -510,3 +512,46 @@ func TestRenderReaderNoContentLength(t *testing.T) {
assert.Equal(t, headers["Content-Disposition"], w.Header().Get("Content-Disposition")) assert.Equal(t, headers["Content-Disposition"], w.Header().Get("Content-Disposition"))
assert.Equal(t, headers["x-request-id"], w.Header().Get("x-request-id")) assert.Equal(t, headers["x-request-id"], w.Header().Get("x-request-id"))
} }
func TestRenderJsonPb(t *testing.T) {
w := httptest.NewRecorder()
reps := []int64{int64(1), int64(2)}
typ := int32(11)
label := "test"
data := &testdata.Test{
Label: &label,
Type: &typ,
Reps: reps,
Optionalgroup: &testdata.Test_OptionalGroup{RequiredField: &label},
}
r := (JSONPB{
Data: data,
datapb: []byte{},
Option: protojson.MarshalOptions{
EmitUnpopulated: true,
},
})
r.WriteContentType(w)
result, err := protojson.MarshalOptions{EmitUnpopulated: true}.Marshal(data)
assert.NoError(t, err)
err = r.Render(w)
assert.NoError(t, err)
assert.Equal(t, string(result), w.Body.String())
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
w1 := httptest.NewRecorder()
r1 := (JSONPB{
Data: nil,
datapb: []byte{},
Option: protojson.MarshalOptions{
EmitUnpopulated: true,
},
})
r1.WriteContentType(w)
result2 := "{}"
err1 := r1.Render(w1)
assert.NoError(t, err1)
assert.Equal(t, result2, w1.Body.String())
assert.Equal(t, "application/json; charset=utf-8", w1.Header().Get("Content-Type"))
}