-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
make available header and trailer metadata #93
Conversation
@@ -208,7 +208,7 @@ var ( | |||
} | |||
{{end}} | |||
|
|||
return client.{{.Method.GetName}}(ctx, &protoReq) | |||
return client.{{.Method.GetName}}(ctx, &protoReq, grpc.Header(&callInfo.HeaderMD), grpc.Trailer(&callInfo.TrailerMD)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These call options are effective only if .Method.GetServerStreaming
and .Method.GetClientStreaming
are false.
The caller of this request_xxx
function must use grpc.ClientStream.Header()
and grpc.ClientStream.Trailer
if otherwise.
IIUC, it would get easier to handle this case if you have let this request_xxx
function allocate the metadata.MD
s and let the function return the MD
s in addition to response and errors.
How about renaming runtime.CallInfo
to runtime.ServerMetadata
and declaring the ! .Method.GetServerStreaming()
version of this function as something like this?
func request_{{.Method.Service.GetName}}_{{.Method.GetName}}_{{.Index}}(ctx context.Context, client {{.Method.Service.GetName}}Client, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error)
With this approach forward_xxx
function does not need to care about .GetClientStreaming
.
Thank you for the comment. I haven't take care streaming because I have never touched. |
Yes. Also I am thinking of forwarding headers and trailers in the forwarder functions. What do you think about it? |
Sorry, I've missed the comment. The metadata are set to context, so we can extract by |
495fa00
to
c33445c
Compare
Addressed comments, but have problems in streaming rpc. Receiving header in stream.
It works well in my small example with streaming, but in integration test it fails sometimes with following error.
I'm not sure why context was canceled. Receiving trailer in stream
|
18c9848
to
6e00a64
Compare
I have fixed metadata handling with some limitations; Dropping support for header metadata in streaming RPC because it's a bit difficult, is it acceptable? And added support to return metadata to client by default.
PTAL @yugui |
Yes. Let me examine it by myself later. But it is acceptable for now.
OK.
It looks weird to put it in response body because it was metadata, and the application-level error does not belong to a specific chunk of body. |
I never knew HTTP 1.1 trailer. I'll try it. |
@yugui I can't find any evidence that any browsers actually support HTTP 1.1. How do you get access to trailers in an XHR object? |
@achew22 Good point. @kazegusuri Although the most straightforward mapping of gRPC trailer metadata is HTTP trailers, there are several things to consider.
|
My first thought is the use case of gRPC trailer is specific for error details, so I attached the metadata to error message for both unary and streaming rpc.
Possible for unary RPC and streaming RPC with client streaming, but impossible for with server streaming.
As described above, yes we cannot use HTTP 1.1 trailer for streaming RPC.
I cannot know how impact to use HTTP 1.1 trailer. |
Yes, it makes sense. Summarizing, I expect the following spec. Is this correct?
|
Not supported for server-streaming and both-streaming RPCs (at least this PR) because header timing issue.
Yes. But for server-streaming and both-streaming, Trailer metadata are returned as an extra chunk of message body. |
You need to call
I am not confident if it is the right solution. So it looks better to conservatively avoid supporting trailer metadata in server-streaming and both-streaming. Is it OK for you? |
Thank you for comment. I will check it out.
Yes. |
67015be
to
8680a68
Compare
I hope all comments addressed and met the spec. |
type serverMetadataKey struct{} | ||
|
||
// NewServerMetadataContext creates a new context with ServerMetadata | ||
func NewServerMetadataContext(ctx context.Context, md *ServerMetadata) context.Context { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC, you no longer need to pass a *ServerMetadata
. You can pass just ServerMetadata
.
Thank you very much. Now the design looks good to me. |
type errorBody struct { | ||
Error string `json:"error"` | ||
Code int `json:"code"` | ||
type ErrorBody struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it is a good idea to expose this type just for testing.
This struct is just a convenient way for this runtime
package to construct JSON object on error. But the struct itself is not a part of API exposed for users or generated codes by this package.
Addressed comments. |
LGTM. Thank you for your excellent contribution. |
make available header and trailer metadata
Thanks! I'm grateful for your help. |
gRPC recommends application-level error information should be returned as Trailer metadata. We have to use
grpc.CallOption
for each rpc call in order to get the metadata at client side. This PR makes protoc-gen-grpc-gateway generates codes withgrpc.CallOption
. And the metadata are set in context, so handlers can extract the metadata byruntime.CallInfoFromContext
.Actually I had a plan to return those metadata as HTTP header or body in JSON especially in
DefaultHTTPError
handler. However metadata possibly includes binary or values must be escaped, so default handler doesn't care metadata by default.EDIT: So I recommend to define a handler which utilizes metadata and overwrite default handlers.
Any ideas or comments are welcome.