mirror of https://github.com/gin-gonic/gin.git
add jsonpb Render
This commit is contained in:
parent
3757142584
commit
ffcd9bf771
|
@ -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{}) {
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -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"))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue