Skip to content
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

refactor mux.go #411

Closed
wants to merge 2 commits into from
Closed

refactor mux.go #411

wants to merge 2 commits into from

Conversation

vaporz
Copy link
Contributor

@vaporz vaporz commented Jun 8, 2017

Code duplication is not good.

@yugui
Copy link
Member

yugui commented Jun 19, 2017

Thank you for your contribution. That's a very good point.
It's definitely the time to simplify the error handling flow.

This PR itself looks good to me. But let me

  • summarize the current status of the handlers,
  • confirm the intention of this PR, and
  • ask some questions to simplify the mechanism even more in a later PR, @vaporz and @kazegusuri.

I'd really appreciate it if you give me some feedback.

The current status

This PR

And this PR is trying to dedupe the implementation by adding two wrapper functions.

  • func (s *ServeMux) executeErrorHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, protoErrorCode codes.Code, protoErrorMsg string, otherStatusCode int, otherErrorMsg string)

    • a wrapper of the overriding mechanism of OtherErrorHandler by ServeMux.protoErrorHandler.
    • uses proto version of error representations if possible, falls back to the plain HTTP version of error representations if otherwise.
  • func executeProtoErrorHandler(ctx context.Context, s *ServeMux, w http.ResponseWriter, r *http.Request, code codes.Code, msg string)

    • a wrapper of HTTPError which determines an appropriate marshaler for it.

Questions

  • @kazegusuri, protoErrorHandler returns 501 Not Implemented instead of 405 Method Not Allowed when the given request method is not allowed (defined) on the resource. Is it really good.
  • @kazegusuri, Was it the reason why you kept DefaultHTTPProtoErrorHandler separated from DefaulHTTPError that DefaultHTTPProtoErrorHandler returns a different format of response body from DefaultHTTPError?
  • @vaporz, The responsibility of executeErrorHandler would be unclear if we only take a look at its signature. Is there any way to simplify it even more? It is totally fine to check it in as is, though.

@vaporz
Copy link
Contributor Author

vaporz commented Jun 19, 2017

hi, @yugui , thanks for your comment.
It took me some time to figure out the relationship between HTTPError, OtherErrorHandler and serveMux.protoErrorHandler.
Now I'm working on a new commit for this PR, a better(hopefully) solution.

@kazegusuri
Copy link
Contributor

@kazegusuri, protoErrorHandler returns 501 Not Implemented instead of 405 Method Not Allowed when the given request method is not allowed (defined) on the resource. Is it really good.

Because gRPC spec says Method not found at server returns UNIMPLEMENTED and the code means 501 Not Implemented in grpc-gateway. However gRPC spec defines HTTP to gRPC Status Code Mapping and it says UNIMPLEMENTED matches 404 Not Found.

Was it the reason why you kept DefaultHTTPProtoErrorHandler separated from DefaulHTTPError

For the first part, actually there is no strong reason, but I wanted to use an option in order to change the behavior of the error handler instead of modify the variable directly.

DefaultHTTPProtoErrorHandler returns a different format of response body from DefaultHTTPError?

The ProtoErrorHandler returns error as status proto, so client can parse the response with the proto.

@vaporz
Copy link
Contributor Author

vaporz commented Jun 19, 2017

Committed, changes are:
1, When NewServeMux, if serveMux.protoErrorHandler is nil, then OtherErrorHandler is adapted for ProtoErrorHandlerFunc, and assigned to serveMux.protoErrorHandler.
2, Return 404/405, instead of 501.

However, I believe this commit is just a start of "error handling mechanism" overhaul.
Here're my thoughts in this topic.

I don't think a HTTP server like grpc-gateway should new a grpc.Status as error and pass them internally. Grpc-gateway should new a gatewayError which contains a grpc.Status(returned by grpc server), and use it internally.
As comments on package status says:

Package status implements errors returned by gRPC. These errors are serialized and transmitted on the wire between server and client,

"between server and client"

I suggest grpc-gateway should transfer grpc.Status error returned by grpc stubs immediately to a gatewayError with HTTP code, message and grpc.Status, then use gatewayError instead of a grpc.Status error.
Whenever an error is returned in grpc-gateway, return a gatewayError.
For example, in *.pb.gw.go, pass a gatewayError to runtime.HTTPError(currently is grpc.Status).
gatewayError may look like this:

type gatewayError struct {
HTTPCode int,
msg string,
status grpc.Status,
}

@vaporz vaporz closed this Oct 10, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants