Skip to content

Commit ee8f8cb

Browse files
committed
Merge pull request #151 from gengo/cleanup/custom-marshaler
Simplify custom marshaler API
2 parents 2c1b1b9 + eadc359 commit ee8f8cb

File tree

12 files changed

+799
-387
lines changed

12 files changed

+799
-387
lines changed

Makefile

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ OPTIONS_PROTO=$(GOOGLEAPIS_DIR)/google/api/annotations.proto $(GOOGLEAPIS_DIR)/g
4141
OPTIONS_GO=$(OPTIONS_PROTO:.proto=.pb.go)
4242
OUTPUT_DIR=_output
4343

44+
RUNTIME_PROTO=runtime/stream_chunk.proto
45+
RUNTIME_GO=$(RUNTIME_PROTO:.proto=.pb.go)
46+
4447
PKGMAP=Mgoogle/protobuf/descriptor.proto=$(GO_PLUGIN_PKG)/descriptor,Mgoogle/api/annotations.proto=$(PKG)/$(GOOGLEAPIS_DIR)/google/api,Mexamples/sub/message.proto=$(PKG)/examples/sub
4548
SWAGGER_EXAMPLES=examples/examplepb/echo_service.proto \
4649
examples/examplepb/streamless_everything.proto
@@ -54,7 +57,7 @@ EXAMPLE_DEPS=examples/sub/message.proto examples/sub2/message.proto
5457
EXAMPLE_DEPSRCS=$(EXAMPLE_DEPS:.proto=.pb.go)
5558
PROTOC_INC_PATH=$(dir $(shell which protoc))/../include
5659

57-
generate: $(OPTIONS_GO)
60+
generate: $(OPTIONS_GO) $(RUNTIME_GO)
5861

5962
.SUFFIXES: .go .proto
6063

@@ -63,9 +66,11 @@ $(GO_PLUGIN):
6366
go build -o $@ $(GO_PLUGIN_PKG)
6467

6568
$(OPTIONS_GO): $(OPTIONS_PROTO) $(GO_PLUGIN)
66-
protoc -I $(PROTOC_INC_PATH) -I$(GOOGLEAPIS_DIR) --plugin=$(GO_PLUGIN) --go_out=$(PKGMAP):$(GOOGLEAPIS_DIR) $(OPTIONS_PROTO)
69+
protoc -I $(PROTOC_INC_PATH) -I$(GOOGLEAPIS_DIR) --plugin=$(GO_PLUGIN) --go_out=$(PKGMAP):$(GOOGLEAPIS_DIR) $(OPTIONS_PROTO)
70+
$(RUNTIME_GO): $(RUNTIME_PROTO) $(GO_PLUGIN)
71+
protoc -I $(PROTOC_INC_PATH) --plugin=$(GO_PLUGIN) -I. --go_out=$(PKGMAP):. $(RUNTIME_PROTO)
6772

68-
$(GATEWAY_PLUGIN): $(OPTIONS_GO) $(GATEWAY_PLUGIN_SRC)
73+
$(GATEWAY_PLUGIN): $(OPTIONS_GO) $(RUNTIME_GO) $(GATEWAY_PLUGIN_SRC)
6974
go build -o $@ $(GATEWAY_PLUGIN_PKG)
7075

7176
$(SWAGGER_PLUGIN): $(OPTIONS_GO) $(SWAGGER_PLUGIN_SRC)

examples/integration_test.go

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package main
22

33
import (
4-
"bytes"
54
"encoding/json"
65
"fmt"
76
"io"
@@ -13,13 +12,13 @@ import (
1312
"testing"
1413
"time"
1514

16-
"golang.org/x/net/context"
17-
1815
gw "github.com/gengo/grpc-gateway/examples/examplepb"
1916
server "github.com/gengo/grpc-gateway/examples/server"
2017
sub "github.com/gengo/grpc-gateway/examples/sub"
2118
"github.com/gengo/grpc-gateway/runtime"
19+
"github.com/golang/protobuf/jsonpb"
2220
"github.com/golang/protobuf/proto"
21+
"golang.org/x/net/context"
2322
"google.golang.org/grpc/codes"
2423
)
2524

@@ -97,8 +96,8 @@ func testEcho(t *testing.T, port int, contentType string) {
9796
}
9897

9998
var msg gw.SimpleMessage
100-
if err := json.Unmarshal(buf, &msg); err != nil {
101-
t.Errorf("json.Unmarshal(%s, &msg) failed with %v; want success", buf, err)
99+
if err := jsonpb.UnmarshalString(string(buf), &msg); err != nil {
100+
t.Errorf("jsonpb.UnmarshalString(%s, &msg) failed with %v; want success", buf, err)
102101
return
103102
}
104103
if got, want := msg.Id, "myid"; got != want {
@@ -112,19 +111,20 @@ func testEcho(t *testing.T, port int, contentType string) {
112111

113112
func testEchoBody(t *testing.T) {
114113
sent := gw.SimpleMessage{Id: "example"}
115-
buf, err := json.Marshal(sent)
114+
var m jsonpb.Marshaler
115+
payload, err := m.MarshalToString(&sent)
116116
if err != nil {
117-
t.Fatalf("json.Marshal(%#v) failed with %v; want success", sent, err)
117+
t.Fatalf("m.MarshalToString(%#v) failed with %v; want success", payload, err)
118118
}
119119

120120
url := "http://localhost:8080/v1/example/echo_body"
121-
resp, err := http.Post(url, "", bytes.NewReader(buf))
121+
resp, err := http.Post(url, "", strings.NewReader(payload))
122122
if err != nil {
123123
t.Errorf("http.Post(%q) failed with %v; want success", url, err)
124124
return
125125
}
126126
defer resp.Body.Close()
127-
buf, err = ioutil.ReadAll(resp.Body)
127+
buf, err := ioutil.ReadAll(resp.Body)
128128
if err != nil {
129129
t.Errorf("iotuil.ReadAll(resp.Body) failed with %v; want success", err)
130130
return
@@ -136,8 +136,8 @@ func testEchoBody(t *testing.T) {
136136
}
137137

138138
var received gw.SimpleMessage
139-
if err := json.Unmarshal(buf, &received); err != nil {
140-
t.Errorf("json.Unmarshal(%s, &msg) failed with %v; want success", buf, err)
139+
if err := jsonpb.UnmarshalString(string(buf), &received); err != nil {
140+
t.Errorf("jsonpb.UnmarshalString(%s, &msg) failed with %v; want success", buf, err)
141141
return
142142
}
143143
if got, want := received, sent; !reflect.DeepEqual(got, want) {
@@ -197,8 +197,8 @@ func testABECreate(t *testing.T) {
197197
}
198198

199199
var msg gw.ABitOfEverything
200-
if err := json.Unmarshal(buf, &msg); err != nil {
201-
t.Errorf("json.Unmarshal(%s, &msg) failed with %v; want success", buf, err)
200+
if err := jsonpb.UnmarshalString(string(buf), &msg); err != nil {
201+
t.Errorf("jsonpb.UnmarshalString(%s, &msg) failed with %v; want success", buf, err)
202202
return
203203
}
204204
if msg.Uuid == "" {
@@ -240,18 +240,19 @@ func testABECreateBody(t *testing.T) {
240240
},
241241
}
242242
url := "http://localhost:8080/v1/example/a_bit_of_everything"
243-
buf, err := json.Marshal(want)
243+
var m jsonpb.Marshaler
244+
payload, err := m.MarshalToString(&want)
244245
if err != nil {
245-
t.Fatalf("json.Marshal(%#v) failed with %v; want success", want, err)
246+
t.Fatalf("m.MarshalToString(%#v) failed with %v; want success", want, err)
246247
}
247248

248-
resp, err := http.Post(url, "application/json", bytes.NewReader(buf))
249+
resp, err := http.Post(url, "application/json", strings.NewReader(payload))
249250
if err != nil {
250251
t.Errorf("http.Post(%q) failed with %v; want success", url, err)
251252
return
252253
}
253254
defer resp.Body.Close()
254-
buf, err = ioutil.ReadAll(resp.Body)
255+
buf, err := ioutil.ReadAll(resp.Body)
255256
if err != nil {
256257
t.Errorf("iotuil.ReadAll(resp.Body) failed with %v; want success", err)
257258
return
@@ -263,8 +264,8 @@ func testABECreateBody(t *testing.T) {
263264
}
264265

265266
var msg gw.ABitOfEverything
266-
if err := json.Unmarshal(buf, &msg); err != nil {
267-
t.Errorf("json.Unmarshal(%s, &msg) failed with %v; want success", buf, err)
267+
if err := jsonpb.UnmarshalString(string(buf), &msg); err != nil {
268+
t.Errorf("jsonpb.UnmarshalString(%s, &msg) failed with %v; want success", buf, err)
268269
return
269270
}
270271
if msg.Uuid == "" {
@@ -316,16 +317,12 @@ func testABEBulkCreate(t *testing.T) {
316317
},
317318
},
318319
}
319-
buf, err := json.Marshal(want)
320-
if err != nil {
321-
t.Fatalf("json.Marshal(%#v) failed with %v; want success", want, err)
322-
}
323-
if _, err := w.Write(buf); err != nil {
324-
t.Errorf("w.Write(%s) failed with %v; want success", buf, err)
325-
return
320+
var m jsonpb.Marshaler
321+
if err := m.Marshal(w, &want); err != nil {
322+
t.Fatalf("m.Marshal(%#v, w) failed with %v; want success", want, err)
326323
}
327324
if _, err := io.WriteString(w, "\n"); err != nil {
328-
t.Errorf("w.Write(%s) failed with %v; want success", buf, err)
325+
t.Errorf("w.Write(%q) failed with %v; want success", "\n", err)
329326
return
330327
}
331328
count++
@@ -350,8 +347,8 @@ func testABEBulkCreate(t *testing.T) {
350347
}
351348

352349
var msg gw.EmptyMessage
353-
if err := json.Unmarshal(buf, &msg); err != nil {
354-
t.Errorf("json.Unmarshal(%s, &msg) failed with %v; want success", buf, err)
350+
if err := jsonpb.UnmarshalString(string(buf), &msg); err != nil {
351+
t.Errorf("jsonpb.UnmarshalString(%s, &msg) failed with %v; want success", buf, err)
355352
return
356353
}
357354

@@ -389,8 +386,8 @@ func testABELookup(t *testing.T) {
389386
}
390387

391388
var want gw.ABitOfEverything
392-
if err := json.Unmarshal(buf, &want); err != nil {
393-
t.Errorf("json.Unmarshal(%s, &want) failed with %v; want success", buf, err)
389+
if err := jsonpb.UnmarshalString(string(buf), &want); err != nil {
390+
t.Errorf("jsonpb.UnmarshalString(%s, &want) failed with %v; want success", buf, err)
394391
return
395392
}
396393

@@ -409,8 +406,8 @@ func testABELookup(t *testing.T) {
409406
}
410407

411408
var msg gw.ABitOfEverything
412-
if err := json.Unmarshal(buf, &msg); err != nil {
413-
t.Errorf("json.Unmarshal(%s, &msg) failed with %v; want success", buf, err)
409+
if err := jsonpb.UnmarshalString(string(buf), &msg); err != nil {
410+
t.Errorf("jsonpb.UnmarshalString(%s, &msg) failed with %v; want success", buf, err)
414411
return
415412
}
416413
if got := msg; !reflect.DeepEqual(got, want) {
@@ -447,7 +444,7 @@ func testABELookupNotFound(t *testing.T) {
447444

448445
var msg errorBody
449446
if err := json.Unmarshal(buf, &msg); err != nil {
450-
t.Errorf("json.Unmarshal(%s, &msg) failed with %v; want success", buf, err)
447+
t.Errorf("jsonpb.UnmarshalString(%s, &msg) failed with %v; want success", buf, err)
451448
return
452449
}
453450

@@ -473,13 +470,24 @@ func testABEList(t *testing.T) {
473470
dec := json.NewDecoder(resp.Body)
474471
var i int
475472
for i = 0; ; i++ {
476-
var msg gw.ABitOfEverything
477-
err := dec.Decode(&msg)
473+
var item struct {
474+
Result json.RawMessage `json:"result"`
475+
Error map[string]interface{} `json:"error"`
476+
}
477+
err := dec.Decode(&item)
478478
if err == io.EOF {
479479
break
480480
}
481481
if err != nil {
482-
t.Errorf("dec.Decode(&msg) failed with %v; want success; i = %d", err, i)
482+
t.Errorf("dec.Decode(&item) failed with %v; want success; i = %d", err, i)
483+
}
484+
if len(item.Error) != 0 {
485+
t.Errorf("item.Error = %#v; want empty; i = %d", item.Error, i)
486+
continue
487+
}
488+
var msg gw.ABitOfEverything
489+
if err := jsonpb.UnmarshalString(string(item.Result), &msg); err != nil {
490+
t.Errorf("jsonpb.UnmarshalString(%s, &msg) failed with %v; want success", item.Result, err)
483491
}
484492
}
485493
if i <= 0 {
@@ -548,8 +556,8 @@ func testAdditionalBindings(t *testing.T) {
548556
}
549557

550558
var msg sub.StringMessage
551-
if err := json.Unmarshal(buf, &msg); err != nil {
552-
t.Errorf("json.Unmarshal(%s, &msg) failed with %v; want success; %d", buf, err, i)
559+
if err := jsonpb.UnmarshalString(string(buf), &msg); err != nil {
560+
t.Errorf("jsonpb.UnmarshalString(%s, &msg) failed with %v; want success; %d", buf, err, i)
553561
return
554562
}
555563
if got, want := msg.GetValue(), "hello"; got != want {

runtime/handler.go

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,6 @@ import (
1212
"google.golang.org/grpc/grpclog"
1313
)
1414

15-
type responseStreamChunk struct {
16-
Result proto.Message `json:"result,omitempty"`
17-
Error *responseStreamError `json:"error,omitempty"`
18-
}
19-
20-
//Make this also conform to proto.Message for builtin JSONPb Marshaler
21-
func (m *responseStreamChunk) Reset() { *m = responseStreamChunk{} }
22-
func (m *responseStreamChunk) String() string { return proto.CompactTextString(m) }
23-
func (*responseStreamChunk) ProtoMessage() {}
24-
25-
type responseStreamError struct {
26-
GrpcCode int `json:"grpc_code,omitempty"`
27-
HTTPCode int `json:"http_code,omitempty"`
28-
Message string `json:"message,omitempty"`
29-
HTTPStatus string `json:"http_status,omitempty"`
30-
}
31-
32-
//Make this also conform to proto.Message for builtin JSONPb Marshaler
33-
func (m *responseStreamError) Reset() { *m = responseStreamError{} }
34-
func (m *responseStreamError) String() string { return proto.CompactTextString(m) }
35-
func (*responseStreamError) ProtoMessage() {}
36-
3715
// ForwardResponseStream forwards the stream from gRPC server to REST client.
3816
func ForwardResponseStream(ctx context.Context, marshaler Marshaler, w http.ResponseWriter, req *http.Request, recv func() (proto.Message, error), opts ...func(context.Context, http.ResponseWriter, proto.Message) error) {
3917
f, ok := w.(http.Flusher)
@@ -73,7 +51,7 @@ func ForwardResponseStream(ctx context.Context, marshaler Marshaler, w http.Resp
7351
return
7452
}
7553

76-
buf, err := marshaler.Marshal(&responseStreamChunk{Result: resp})
54+
buf, err := marshaler.Marshal(streamChunk(resp, nil))
7755
if err != nil {
7856
grpclog.Printf("Failed to marshal response chunk: %v", err)
7957
return
@@ -154,16 +132,7 @@ func handleForwardResponseOptions(ctx context.Context, w http.ResponseWriter, re
154132
}
155133

156134
func handleForwardResponseStreamError(marshaler Marshaler, w http.ResponseWriter, err error) {
157-
grpcCode := grpc.Code(err)
158-
httpCode := HTTPStatusFromCode(grpcCode)
159-
resp := &responseStreamChunk{
160-
Error: &responseStreamError{
161-
GrpcCode: int(grpcCode),
162-
HTTPCode: httpCode,
163-
Message: err.Error(),
164-
HTTPStatus: http.StatusText(httpCode),
165-
}}
166-
buf, merr := marshaler.Marshal(resp)
135+
buf, merr := marshaler.Marshal(streamChunk(nil, err))
167136
if merr != nil {
168137
grpclog.Printf("Failed to marshal an error: %v", merr)
169138
return
@@ -173,3 +142,22 @@ func handleForwardResponseStreamError(marshaler Marshaler, w http.ResponseWriter
173142
return
174143
}
175144
}
145+
146+
func streamChunk(result proto.Message, err error) map[string]proto.Message {
147+
if err != nil {
148+
grpcCode := grpc.Code(err)
149+
httpCode := HTTPStatusFromCode(grpcCode)
150+
return map[string]proto.Message{
151+
"error": &StreamError{
152+
GrpcCode: int32(grpcCode),
153+
HttpCode: int32(httpCode),
154+
Message: err.Error(),
155+
HttpStatus: http.StatusText(httpCode),
156+
},
157+
}
158+
}
159+
if result == nil {
160+
return streamChunk(nil, fmt.Errorf("empty response"))
161+
}
162+
return map[string]proto.Message{"result": result}
163+
}

0 commit comments

Comments
 (0)