-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
status: Allow external packages to produce status-compatible errors #1927
Conversation
Thank you for your pull request. Before we can look at your contribution, we need to ensure all contributors are covered by a Contributor License Agreement. After the following items are addressed, please respond with a new comment here, and the automated system will re-verify.
Regards, |
I've signed the CLA |
d16829c
to
6b7bae6
Compare
Thanks for the PR. Instead of this approach, what if |
@dfawley That's certainly a middle ground, and better than today, but unfortunately it's still not a very ergonomic experience for users of gogoproto registered types. I think it would look something like this: package server
import (
"context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
spb "google.golang.org/genproto/googleapis/rpc/status"
"github.com/gogo/googleapis/google/rpc"
"github.com/golang/protobuf/ptypes/any"
"github.com/gogo/protobuf/proto"
)
func GetError(ctx context.Context, req *rpc.DebugInfo) (*rpc.DebugInfo, error) {
st := status.New(codes.InvalidArgument, "some error")
br := &rpc.BadRequest{
FieldViolations: []*rpc.BadRequest_FieldViolation{
{
Field: "Some field",
Description: "Some error description",
},
},
}
byts, err := proto.Marshal(br)
if err != nil {
return nil, err
}
stWithDetails, err := st.WithDetails(&any.Any{
TypeUrl: "type.googleapis.com/" + proto.MessageName(br)
Value: byts
})
if err != nil {
return nil, st.Err()
}
return nil, stWithDetails.Err()
} This isn't all that much better than just constructing the
The approach taken in this PR would allow something like this instead (using https://github.com/gogo/status in place of the gRPC status package): package server
import (
"context"
"github.com/gogo/googleapis/google/rpc"
"github.com/gogo/status"
"google.golang.org/grpc/codes"
)
func GetError(ctx context.Context, req *rpc.DebugInfo) (*rpc.DebugInfo, error) {
st := status.New(codes.InvalidArgument, "some error")
stWithDetails, err := st.WithDetails(&rpc.BadRequest{
FieldViolations: []*rpc.BadRequest_FieldViolation{
{
Field: "Some field",
Description: "Some error description",
},
},
})
if err != nil {
return nil, st.Err()
}
return nil, stWithDetails.Err()
} Because I hope that further clarifies the intent. Please see my blog post on errors, in particular the problems associated with using GoGo protobuf with the gRPC status package for more information: https://jbrandhorst.com/post/grpc-errors/. |
@johanbrandhorst Thank you for the code samples. However, the second sample doesn't really look right for what is proposed in this PR. You should show Also, what is the concern with using |
I think you misunderstood the point of my reply. I was showing the implications of this PR versus the implications of your suggestion, for gogoproto users, when creating a status error. The I pointed you to https://github.com/gogo/status which indeed implements the proposed interface: I further direct you to the implementation of gogo/status.FromError to give you the full picture: Indeed, just to be explicit, the point of this PR is to allow gogo/protobuf users to work effortlessly within the gogo/protobuf ecosystem which they are forced to by the design of the golang/protobuf project. The interface is created so that we can return |
OK, so you want this so applications can return a I would prefer to do this slightly differently:
This was actually part of an earlier implementation, but I made it more restrictive, because this use case was not apparent at the time. I think this would have all the same benefits for you, but it would keep things simpler and easier to understand in our API. What do you think? |
@dfawley that sounds promising, I'll give it a go and update the PR when I have a moment. Thanks! |
6b7bae6
to
106d5c0
Compare
I've given this some testing, and it works just as well as the previously suggested code, so I've updated the PR with the simpler interface. |
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.
Looks good, thanks! Just one request to change the docstring to advertise this new functionality.
@@ -126,8 +126,8 @@ func FromError(err error) (s *Status, ok bool) { | |||
if err == nil { | |||
return &Status{s: &spb.Status{Code: int32(codes.OK)}}, true | |||
} | |||
if se, ok := err.(*statusError); ok { | |||
return se.status(), true | |||
if se, ok := err.(interface{ Status() *Status }); ok { |
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.
Could you change the docstring to say "if it was produced from this package or has a method Status() *Status
"
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.
Done
Embues the status package with the ability to create statuses from generic errors that implement the interface: type StatusError interface { Status() *Status } This was designed with the github.com/gogo/protobuf project in mind, but is implemented in a fashion that makes it accessible to arbitrary payloads. Fixes grpc#1885.
106d5c0
to
64d5527
Compare
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.
Thank you again for the contribution!
🎉 thanks a lot! Excited to see this go in :). |
Embues the status package with the ability to create statuses
from generic errors that implement a special interface.
This was designed with the github.com/gogo/protobuf project in mind,
but is implemented in a fashion that makes it accessible to arbitrary
payloads.
Fixes #1885.