Commit a1b0988
authored
feat: Add WithForwardResponseRewriter to allow easier/more useful response control (#4622)
## Context/Background
I am working with grpc-gateway to mimick an older REST API while
implementing the core as a gRPC server. This REST API, by convention,
emits a response envelope.
After extensively researching grpc-gateway's code and options, I think
that there is not a good enough way to address my use-case; for a few
more nuanced reasons.
The sum of my requirements are as follows:
- 1) Allow a particular field of a response message to be used as the main
response. ✅ This is handled with `response_body` annotation.
- 2) Be able to run interface checks on the response to extract useful
information, like `next_page_token` [0] and surface it in the final
response envelope. (`npt, ok := resp.(interface { GetNextPageToken() string })`).
- 3) Take the true result and place it into a response envelope along with
other parts of the response by convention and let that be encoded and
sent as the response instead.
### Implementing a response envelope with `Marshaler`
My first attempt at getting my gRPC server's responses in an envelope
led me to implement my own Marshaler, I have seen this approach
discussed in #4483.
This does satisfy requirements 1 and 3 just fine, since the HTTP
annotations helpfully allow the code to only receive the true result,
and the Marshal interface has enough capabilities to take that and wrap
it in a response envelope.
However, requirements 1 and 2 are not _both_ satisfiable with the
current grpc-gateway code because of how the `XXX_ResponseBody()` is
called _before_ passing to the `Marshal(v)` function. This strips out
the other fields that I would normally be able to detect and place in
the response envelope.
I even tried creating my _own_ protobuf message extension that would let
me define another way of defining the "true result" field. But the
options for implementing that are either a _ton_ of protoreflect at
runtime to detect and extract that, or I am writing another protobuf
generator plugin (which I have done before [1]), but both of those
options seem quite complex.
### Other non-starter options
Just to get ahead of the discussion, `WithForwardResponseOption` clearly
was not meant for this use-case. At best, it seems to only be a way to
take information that might be in the response and add it as a header.
[0]: https://google.aip.dev/158#:~:text=Response%20messages%20for%20collections%20should%20define%20a%20string%20next_page_token%20field
[1]: https://github.com/nkcmr/protoc-gen-twirp_js
### In practice
This change fulfills my requirements by allowing logic to be inserted
right before the Marshal is called:
```go
gatewayMux := runtime.NewServeMux(
runtime.WithForwardResponseRewriter(func(ctx context.Context, response proto.Message) (interface{}, error) {
if s, ok := response.(*statuspb.Status); ok {
return rewriteStatusToErrorEnvelope(ctx, s)
}
return rewriteResultToEnvelope(ctx, response)
}),
)
```
## In this PR
This PR introduces a new `ServeMuxOption` called
`WithForwardResponseRewriter` that allows for a user-provided function
to be supplied that can take a response `proto.Message` and return `any`
during unary response forwarding, stream response forwarding, and error
response forwarding.
The code generation was also updated to make the `XXX_ResponseBody()`
response wrappers embed the concrete type instead of just
`proto.Message`. This allows any code in response rewriter functions to
be able to have access to the original type, so that interface checks
against it should pass as if it was the original message.
Updated the "Customizing Your Gateway" documentation to use
`WithForwardResponseRewriter` in the `Fully Overriding Custom HTTP
Responses` sections.
## Testing
Added some basic unit tests to ensure Unary/Stream and error handlers
invoke `ForwardResponseRewriter` correctly.1 parent 169370b commit a1b0988
File tree
8 files changed
+156
-74
lines changed- docs/docs/mapping
- examples/internal/proto/examplepb
- protoc-gen-grpc-gateway/internal/gengateway
- runtime
8 files changed
+156
-74
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
324 | 324 | | |
325 | 325 | | |
326 | 326 | | |
327 | | - | |
328 | | - | |
| 327 | + | |
| 328 | + | |
329 | 329 | | |
330 | 330 | | |
331 | 331 | | |
332 | | - | |
| 332 | + | |
333 | 333 | | |
334 | 334 | | |
335 | | - | |
| 335 | + | |
336 | 336 | | |
337 | 337 | | |
338 | 338 | | |
| |||
342 | 342 | | |
343 | 343 | | |
344 | 344 | | |
345 | | - | |
| 345 | + | |
346 | 346 | | |
347 | 347 | | |
348 | | - | |
349 | | - | |
350 | | - | |
351 | | - | |
352 | | - | |
353 | | - | |
| 348 | + | |
354 | 349 | | |
355 | 350 | | |
356 | 351 | | |
357 | | - | |
| 352 | + | |
358 | 353 | | |
359 | 354 | | |
360 | | - | |
| 355 | + | |
361 | 356 | | |
362 | | - | |
363 | | - | |
| 357 | + | |
364 | 358 | | |
365 | 359 | | |
366 | 360 | | |
367 | 361 | | |
368 | 362 | | |
369 | | - | |
370 | | - | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
371 | 368 | | |
372 | 369 | | |
373 | 370 | | |
| |||
Lines changed: 14 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
654 | 654 | | |
655 | 655 | | |
656 | 656 | | |
657 | | - | |
| 657 | + | |
658 | 658 | | |
659 | 659 | | |
660 | 660 | | |
| |||
744 | 744 | | |
745 | 745 | | |
746 | 746 | | |
747 | | - | |
| 747 | + | |
748 | 748 | | |
749 | 749 | | |
750 | 750 | | |
| |||
759 | 759 | | |
760 | 760 | | |
761 | 761 | | |
762 | | - | |
| 762 | + | |
763 | 763 | | |
764 | 764 | | |
765 | 765 | | |
766 | | - | |
767 | | - | |
| 766 | + | |
768 | 767 | | |
769 | 768 | | |
770 | 769 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
93 | 93 | | |
94 | 94 | | |
95 | 95 | | |
| 96 | + | |
96 | 97 | | |
97 | 98 | | |
98 | 99 | | |
99 | 100 | | |
100 | 101 | | |
101 | 102 | | |
102 | 103 | | |
103 | | - | |
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
107 | 107 | | |
108 | | - | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
109 | 119 | | |
110 | 120 | | |
111 | 121 | | |
112 | 122 | | |
113 | 123 | | |
114 | 124 | | |
115 | | - | |
| 125 | + | |
116 | 126 | | |
117 | 127 | | |
118 | 128 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| |||
24 | 25 | | |
25 | 26 | | |
26 | 27 | | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
33 | 36 | | |
34 | 37 | | |
35 | 38 | | |
| |||
70 | 73 | | |
71 | 74 | | |
72 | 75 | | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
73 | 93 | | |
74 | 94 | | |
75 | 95 | | |
76 | 96 | | |
77 | | - | |
78 | | - | |
79 | | - | |
80 | 97 | | |
81 | | - | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
82 | 107 | | |
83 | 108 | | |
84 | 109 | | |
85 | 110 | | |
86 | 111 | | |
87 | 112 | | |
88 | 113 | | |
89 | | - | |
| 114 | + | |
90 | 115 | | |
91 | 116 | | |
92 | 117 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
56 | 56 | | |
57 | 57 | | |
58 | 58 | | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
59 | 66 | | |
60 | | - | |
| 67 | + | |
61 | 68 | | |
62 | 69 | | |
63 | 70 | | |
64 | | - | |
| 71 | + | |
65 | 72 | | |
66 | | - | |
| 73 | + | |
67 | 74 | | |
68 | 75 | | |
69 | 76 | | |
70 | 77 | | |
71 | | - | |
72 | | - | |
| 78 | + | |
| 79 | + | |
73 | 80 | | |
74 | 81 | | |
75 | 82 | | |
| |||
165 | 172 | | |
166 | 173 | | |
167 | 174 | | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
168 | 181 | | |
169 | | - | |
170 | | - | |
| 182 | + | |
171 | 183 | | |
172 | 184 | | |
173 | | - | |
| 185 | + | |
174 | 186 | | |
175 | 187 | | |
176 | 188 | | |
| |||
0 commit comments