Skip to content

Commit 5f308a6

Browse files
Tidy up docs
1 parent 9e8664e commit 5f308a6

File tree

8 files changed

+270
-326
lines changed

8 files changed

+270
-326
lines changed

docs/_docs/customizingyourgateway.md

Lines changed: 97 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,29 @@ You might want to serialize request/response messages in MessagePack instead of
1313

1414
1. Write a custom implementation of [`Marshaler`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime?tab=doc#Marshaler)
1515
2. Register your marshaler with [`WithMarshalerOption`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime?tab=doc#WithMarshalerOption)
16-
e.g.
17-
```go
18-
var m your.MsgPackMarshaler
19-
mux := runtime.NewServeMux(runtime.WithMarshalerOption("application/x-msgpack", m))
20-
```
16+
e.g.
17+
```go
18+
var m your.MsgPackMarshaler
19+
mux := runtime.NewServeMux(
20+
runtime.WithMarshalerOption("application/x-msgpack", m),
21+
)
22+
```
2123

2224
You can see [the default implementation for JSON](https://github.com/grpc-ecosystem/grpc-gateway/blob/master/runtime/marshal_jsonpb.go) for reference.
2325

2426
### Using camelCase for JSON
2527

2628
The protocol buffer compiler generates camelCase JSON tags that can be used with jsonpb package. By default jsonpb Marshaller uses `OrigName: true` which uses the exact case used in the proto files. To use camelCase for the JSON representation,
27-
```go
28-
mux := runtime.NewServeMux(runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{OrigName:false}))
29-
```
29+
```go
30+
mux := runtime.NewServeMux(runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{OrigName:false}))
31+
```
3032

3133
### Pretty-print JSON responses when queried with ?pretty
3234

3335
You can have Elasticsearch-style `?pretty` support in your gateway's endpoints as follows:
3436

3537
1. Wrap the ServeMux using a stdlib [`http.HandlerFunc`](https://golang.org/pkg/net/http/#HandlerFunc)
36-
that translates the provided query parameter into a custom `Accept` header, and
38+
that translates the provided query parameter into a custom `Accept` header, and
3739
2. Register a pretty-printing marshaler for that MIME code.
3840

3941
For example:
@@ -112,11 +114,10 @@ default marshaler options:
112114

113115
```go
114116
mux := runtime.NewServeMux(
115-
runtime.WithMarshalerOption("application/json+strict",
116-
&m{
117-
JSONPb: &runtime.JSONPb{EmitDefaults: true},
118-
unmarshaler: &jsonpb.Unmarshaler{AllowUnknownFields: false}, // explicit "false", &jsonpb.Unmarshaler{} would have the same effect
119-
}),
117+
runtime.WithMarshalerOption("application/json+strict", &m{
118+
JSONPb: &runtime.JSONPb{EmitDefaults: true},
119+
unmarshaler: &jsonpb.Unmarshaler{AllowUnknownFields: false}, // explicit "false", &jsonpb.Unmarshaler{} would have the same effect
120+
}),
120121
)
121122
```
122123

@@ -126,131 +127,127 @@ You might not like [the default mapping rule](https://pkg.go.dev/github.com/grpc
126127
1. Write a [`HeaderMatcherFunc`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime?tab=doc#HeaderMatcherFunc).
127128
2. Register the function with [`WithIncomingHeaderMatcher`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime?tab=doc#WithIncomingHeaderMatcher)
128129

129-
e.g.
130-
```go
131-
func CustomMatcher(key string) (string, bool) {
132-
switch key {
133-
case "X-Custom-Header1":
134-
return key, true
135-
case "X-Custom-Header2":
136-
return "custom-header2", true
137-
default:
138-
return key, false
139-
}
140-
}
141-
...
142-
143-
mux := runtime.NewServeMux(runtime.WithIncomingHeaderMatcher(CustomMatcher))
144-
```
130+
e.g.
131+
```go
132+
func CustomMatcher(key string) (string, bool) {
133+
switch key {
134+
case "X-Custom-Header1":
135+
return key, true
136+
case "X-Custom-Header2":
137+
return "custom-header2", true
138+
default:
139+
return key, false
140+
}
141+
}
142+
143+
mux := runtime.NewServeMux(
144+
runtime.WithIncomingHeaderMatcher(CustomMatcher),
145+
)
146+
```
147+
145148
To keep the [the default mapping rule](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime?tab=doc#DefaultHeaderMatcher) alongside with your own rules write:
146149

147150
```go
148151
func CustomMatcher(key string) (string, bool) {
149-
switch key {
150-
case "X-User-Id":
151-
return key, true
152-
default:
153-
return runtime.DefaultHeaderMatcher(key)
154-
}
152+
switch key {
153+
case "X-User-Id":
154+
return key, true
155+
default:
156+
return runtime.DefaultHeaderMatcher(key)
157+
}
155158
}
156159
```
157160
It will work with both:
158161

159-
```bash
160-
curl --header "x-user-id: 100d9f38-2777-4ee2-ac3b-b3a108f81a30" ...
162+
```shell
163+
$ curl --header "x-user-id: 100d9f38-2777-4ee2-ac3b-b3a108f81a30" ...
161164
```
162165
and:
163-
```bash
164-
curl --header "X-USER-ID: 100d9f38-2777-4ee2-ac3b-b3a108f81a30" ...
166+
```shell
167+
$ curl --header "X-USER-ID: 100d9f38-2777-4ee2-ac3b-b3a108f81a30" ...
165168
```
166169
To access this header on gRPC server side use:
167170
```go
168-
...
169171
userID := ""
170172
if md, ok := metadata.FromIncomingContext(ctx); ok {
171-
if uID, ok := md["x-user-id"]; ok {
172-
userID = strings.Join(uID, ",")
173-
}
173+
if uID, ok := md["x-user-id"]; ok {
174+
userID = strings.Join(uID, ",")
175+
}
174176
}
175-
...
176177
```
177178

178179
## Mapping from gRPC server metadata to HTTP response headers
179180
ditto. Use [`WithOutgoingHeaderMatcher`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime?tab=doc#WithOutgoingHeaderMatcher).
180181
See [gRPC metadata docs](https://github.com/grpc/grpc-go/blob/master/Documentation/grpc-metadata.md)
181-
for more info on sending / receiving gRPC metadata.
182-
183-
e.g.
184-
185-
```go
186-
...
187-
if appendCustomHeader {
188-
grpc.SendHeader(ctx, metadata.New(map[string]string{
189-
"x-custom-header1": "value",
190-
}))
191-
}
192-
```
182+
for more info on sending / receiving gRPC metadata, e.g.
183+
```go
184+
if appendCustomHeader {
185+
grpc.SendHeader(ctx, metadata.New(map[string]string{
186+
"x-custom-header1": "value",
187+
}))
188+
}
189+
```
193190

194191
## Mutate response messages or set response headers
195192
You might want to return a subset of response fields as HTTP response headers;
196193
You might want to simply set an application-specific token in a header.
197194
Or you might want to mutate the response messages to be returned.
198195

199196
1. Write a filter function.
200-
```go
201-
func myFilter(ctx context.Context, w http.ResponseWriter, resp proto.Message) error {
202-
t, ok := resp.(*externalpb.Tokenizer)
203197

204-
if ok {
205-
w.Header().Set("X-My-Tracking-Token", t.Token)
206-
t.Token = ""
198+
```go
199+
func myFilter(ctx context.Context, w http.ResponseWriter, resp proto.Message) error {
200+
t, ok := resp.(*externalpb.Tokenizer)
201+
if ok {
202+
w.Header().Set("X-My-Tracking-Token", t.Token)
203+
t.Token = ""
204+
}
205+
return nil
207206
}
208-
209-
return nil
210-
}
211-
```
207+
```
212208
2. Register the filter with [`WithForwardResponseOption`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime?tab=doc#WithForwardResponseOption)
213209

214-
e.g.
215-
```go
216-
mux := runtime.NewServeMux(runtime.WithForwardResponseOption(myFilter))
217-
```
210+
e.g.
211+
```go
212+
mux := runtime.NewServeMux(
213+
runtime.WithForwardResponseOption(myFilter),
214+
)
215+
```
218216

219217
## OpenTracing Support
220218

221219
If your project uses [OpenTracing](https://github.com/opentracing/opentracing-go) and you'd like spans to propagate through the gateway, you can add some middleware which parses the incoming HTTP headers to create a new span correctly.
222220

223221
```go
224222
import (
225-
...
226-
"github.com/opentracing/opentracing-go"
227-
"github.com/opentracing/opentracing-go/ext"
223+
"github.com/opentracing/opentracing-go"
224+
"github.com/opentracing/opentracing-go/ext"
228225
)
229226

230227
var grpcGatewayTag = opentracing.Tag{Key: string(ext.Component), Value: "grpc-gateway"}
231228

232229
func tracingWrapper(h http.Handler) http.Handler {
233-
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
234-
parentSpanContext, err := opentracing.GlobalTracer().Extract(
235-
opentracing.HTTPHeaders,
236-
opentracing.HTTPHeadersCarrier(r.Header))
237-
if err == nil || err == opentracing.ErrSpanContextNotFound {
238-
serverSpan := opentracing.GlobalTracer().StartSpan(
239-
"ServeHTTP",
240-
// this is magical, it attaches the new span to the parent parentSpanContext, and creates an unparented one if empty.
241-
ext.RPCServerOption(parentSpanContext),
242-
grpcGatewayTag,
243-
)
244-
r = r.WithContext(opentracing.ContextWithSpan(r.Context(), serverSpan))
245-
defer serverSpan.Finish()
246-
}
247-
h.ServeHTTP(w, r)
248-
})
230+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
231+
parentSpanContext, err := opentracing.GlobalTracer().Extract(
232+
opentracing.HTTPHeaders,
233+
opentracing.HTTPHeadersCarrier(r.Header))
234+
if err == nil || err == opentracing.ErrSpanContextNotFound {
235+
serverSpan := opentracing.GlobalTracer().StartSpan(
236+
"ServeHTTP",
237+
// this is magical, it attaches the new span to the parent parentSpanContext, and creates an unparented one if empty.
238+
ext.RPCServerOption(parentSpanContext),
239+
grpcGatewayTag,
240+
)
241+
r = r.WithContext(opentracing.ContextWithSpan(r.Context(), serverSpan))
242+
defer serverSpan.Finish()
243+
}
244+
h.ServeHTTP(w, r)
245+
})
249246
}
250247

251248
// Then just wrap the mux returned by runtime.NewServeMux() like this
252249
if err := http.ListenAndServe(":8080", tracingWrapper(mux)); err != nil {
253-
log.Fatalf("failed to start gateway server on 8080: %v", err)
250+
log.Fatalf("failed to start gateway server on 8080: %v", err)
254251
}
255252
```
256253

@@ -259,17 +256,16 @@ the services. E.g.
259256

260257
```go
261258
import (
262-
...
263-
"google.golang.org/grpc"
264-
"github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing"
259+
"google.golang.org/grpc"
260+
"github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing"
265261
)
266262

267263
opts := []grpc.DialOption{
268-
grpc.WithUnaryInterceptor(
269-
grpc_opentracing.UnaryClientInterceptor(
270-
grpc_opentracing.WithTracer(opentracing.GlobalTracer()),
271-
),
272-
),
264+
grpc.WithUnaryInterceptor(
265+
grpc_opentracing.UnaryClientInterceptor(
266+
grpc_opentracing.WithTracer(opentracing.GlobalTracer()),
267+
),
268+
),
273269
}
274270
if err := pb.RegisterMyServiceHandlerFromEndpoint(ctx, mux, serviceEndpoint, opts); err != nil {
275271
log.Fatalf("could not register HTTP service: %v", err)
@@ -312,7 +308,8 @@ streams, you must install a _different_ error handler:
312308

313309
```go
314310
mux := runtime.NewServeMux(
315-
runtime.WithStreamErrorHandler(handleStreamError))
311+
runtime.WithStreamErrorHandler(handleStreamError),
312+
)
316313
```
317314

318315
The signature of the handler is much more rigid because we need
@@ -362,34 +359,3 @@ these attributes, a gRPC code of `Unknown` (2) is reported. The default
362359
handler will also include an HTTP code and status, which is derived
363360
from the gRPC code (or set to `"500 Internal Server Error"` when
364361
the source error has no gRPC attributes).
365-
366-
## Replace a response forwarder per method
367-
You might want to keep the behavior of the current marshaler but change only a message forwarding of a certain API method.
368-
369-
1. write a custom forwarder which is compatible to [`ForwardResponseMessage`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime?tab=doc#ForwardResponseMessage) or [`ForwardResponseStream`](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime?tab=doc#ForwardResponseStream).
370-
2. replace the default forwarder of the method with your one.
371-
372-
e.g. add `forwarder_overwrite.go` into the go package of the generated code,
373-
```go
374-
package generated
375-
376-
import (
377-
"net/http"
378-
379-
"github.com/grpc-ecosystem/grpc-gateway/runtime"
380-
"github.com/golang/protobuf/proto"
381-
"golang.org/x/net/context"
382-
)
383-
384-
func forwardCheckoutResp(ctx context.Context, mux *runtime.ServeMux, marshaler runtime.Marshaler, w http.ResponseWriter, req *http.Request, resp proto.Message, opts ...func(context.Context, http.ResponseWriter, proto.Message) error) {
385-
if someCondition(resp) {
386-
http.Error(w, "not enough credit", http. StatusPaymentRequired)
387-
return
388-
}
389-
runtime.ForwardResponseMessage(ctx, mux, marshaler, w, req, resp, opts...)
390-
}
391-
392-
func init() {
393-
forward_MyService_Checkout_0 = forwardCheckoutResp
394-
}
395-
```

docs/_docs/examples.md

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,29 @@ category: documentation
55
# Examples
66

77
Examples are available under `examples/internal` directory.
8-
* `proto/examplepb/echo_service.proto`, `proto/examplepb/a_bit_of_everything.proto`, `proto/examplepb/unannotated_echo_service.proto`: service definition
9-
* `proto/examplepb/echo_service.pb.go`, `proto/examplepb/a_bit_of_everything.pb.go`, `proto/examplepb/unannotated_echo_service.pb.go`: [generated] stub of the service
10-
* `proto/examplepb/echo_service.pb.gw.go`, `proto/examplepb/a_bit_of_everything.pb.gw.go`, `proto/examplepb/uannotated_echo_service.pb.gw.go`: [generated] reverse proxy for the service
11-
* `proto/examplepb/unannotated_echo_service.yaml`: gRPC API Configuration for ```unannotated_echo_service.proto```
12-
* `server/main.go`: service implementation
13-
* `main.go`: entrypoint of the generated reverse proxy
8+
* [`proto/examplepb/echo_service.proto`](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/examples/internal/proto/examplepb/echo_service.proto),
9+
[`proto/examplepb/a_bit_of_everything.proto`](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/examples/internal/proto/examplepb/a_bit_of_everything.proto),
10+
[`proto/examplepb/unannotated_echo_service.proto`](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/examples/internal/proto/examplepb/unannotated_echo_service.proto):
11+
protobuf service definitions.
12+
* [`proto/examplepb/echo_service.pb.go`](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/examples/internal/proto/examplepb/echo_service.pb.go),
13+
[`proto/examplepb/a_bit_of_everything.pb.go`](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/examples/internal/proto/examplepb/a_bit_of_everything.pb.go),
14+
[`proto/examplepb/unannotated_echo_service.pb.go`](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/examples/internal/proto/examplepb/unannotated_echo_service.pb.go):
15+
generated Go service stubs and types.
16+
* [`proto/examplepb/echo_service.pb.gw.go`](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/examples/internal/proto/examplepb/echo_service.pb.gw.go),
17+
[`proto/examplepb/a_bit_of_everything.pb.gw.go`](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/examples/internal/proto/examplepb/a_bit_of_everything.pb.gw.go),
18+
[`proto/examplepb/uannotated_echo_service.pb.gw.go`](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/examples/internal/proto/examplepb/uannotated_echo_service.pb.gw.go):
19+
generated gRPC-gateway clients.
20+
* [`proto/examplepb/unannotated_echo_service.yaml`](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/examples/internal/proto/examplepb/uannotated_echo_service.yaml):
21+
gRPC API Configuration for `unannotated_echo_service.proto`.
22+
* [`server/main.go`](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/examples/internal/server/main.go):
23+
service implementation.
24+
* [`main.go`](https://github.com/grpc-ecosystem/grpc-gateway/tree/master/examples/internal/gateway/main.go):
25+
entrypoint of the generated reverse proxy.
1426

15-
To use the same port for custom HTTP handlers (e.g. serving `swagger.json`), gRPC-gateway, and a gRPC server, see [this code example by CoreOS](https://github.com/philips/grpc-gateway-example/blob/master/cmd/serve.go) (and its accompanying [blog post](https://coreos.com/blog/grpc-protobufs-swagger.html))
27+
To use the same port for custom HTTP handlers (e.g. serving `swagger.json`),
28+
gRPC-gateway, and a gRPC server, see
29+
[this code example by CoreOS](https://github.com/philips/grpc-gateway-example/blob/master/cmd/serve.go)
30+
(and its accompanying
31+
[blog post](https://coreos.com/blog/grpc-protobufs-swagger.html))
1632

1733

0 commit comments

Comments
 (0)