mirror of
https://github.com/go-kit/kit.git
synced 2025-07-17 01:12:38 +02:00
Merge pull request #287 from go-kit/addsvc-errors
examples/addsvc: more sophisticated error encoding
This commit is contained in:
@ -42,7 +42,7 @@ func (e Endpoints) Sum(ctx context.Context, a, b int) (int, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return response.(sumResponse).V, nil
|
||||
return response.(sumResponse).V, response.(sumResponse).Err
|
||||
}
|
||||
|
||||
// Concat implements Service. Primarily useful in a client.
|
||||
@ -52,7 +52,7 @@ func (e Endpoints) Concat(ctx context.Context, a, b string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return response.(concatResponse).V, err
|
||||
return response.(concatResponse).V, response.(concatResponse).Err
|
||||
}
|
||||
|
||||
// MakeSumEndpoint returns an endpoint that invokes Sum on the service.
|
||||
@ -61,11 +61,12 @@ func MakeSumEndpoint(s Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
|
||||
sumReq := request.(sumRequest)
|
||||
v, err := s.Sum(ctx, sumReq.A, sumReq.B)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if err == ErrIntOverflow {
|
||||
return nil, err // special case; see comment on ErrIntOverflow
|
||||
}
|
||||
return sumResponse{
|
||||
V: v,
|
||||
V: v,
|
||||
Err: err,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
@ -76,11 +77,9 @@ func MakeConcatEndpoint(s Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
|
||||
concatReq := request.(concatRequest)
|
||||
v, err := s.Concat(ctx, concatReq.A, concatReq.B)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return concatResponse{
|
||||
V: v,
|
||||
V: v,
|
||||
Err: err,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
@ -124,8 +123,14 @@ func EndpointLoggingMiddleware(logger log.Logger) endpoint.Middleware {
|
||||
|
||||
type sumRequest struct{ A, B int }
|
||||
|
||||
type sumResponse struct{ V int }
|
||||
type sumResponse struct {
|
||||
V int
|
||||
Err error
|
||||
}
|
||||
|
||||
type concatRequest struct{ A, B string }
|
||||
|
||||
type concatResponse struct{ V string }
|
||||
type concatResponse struct {
|
||||
V string
|
||||
Err error
|
||||
}
|
||||
|
@ -47,7 +47,8 @@ func (*SumRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{
|
||||
|
||||
// The sum response contains the result of the calculation.
|
||||
type SumReply struct {
|
||||
V int64 `protobuf:"varint,1,opt,name=v" json:"v,omitempty"`
|
||||
V int64 `protobuf:"varint,1,opt,name=v" json:"v,omitempty"`
|
||||
Err string `protobuf:"bytes,2,opt,name=err" json:"err,omitempty"`
|
||||
}
|
||||
|
||||
func (m *SumReply) Reset() { *m = SumReply{} }
|
||||
@ -68,7 +69,8 @@ func (*ConcatRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []i
|
||||
|
||||
// The Concat response contains the result of the concatenation.
|
||||
type ConcatReply struct {
|
||||
V string `protobuf:"bytes,1,opt,name=v" json:"v,omitempty"`
|
||||
V string `protobuf:"bytes,1,opt,name=v" json:"v,omitempty"`
|
||||
Err string `protobuf:"bytes,2,opt,name=err" json:"err,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ConcatReply) Reset() { *m = ConcatReply{} }
|
||||
@ -192,16 +194,17 @@ var _Add_serviceDesc = grpc.ServiceDesc{
|
||||
}
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 174 bytes of a gzipped FileDescriptorProto
|
||||
// 188 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x49, 0x4c, 0x49, 0x29,
|
||||
0x2e, 0x4b, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2a, 0x48, 0x52, 0xd2, 0xe0, 0xe2,
|
||||
0x0a, 0x2e, 0xcd, 0x0d, 0x4a, 0x2d, 0x2c, 0x4d, 0x2d, 0x2e, 0x11, 0xe2, 0xe1, 0x62, 0x4c, 0x94,
|
||||
0x60, 0x54, 0x60, 0xd4, 0x60, 0x0e, 0x62, 0x4c, 0x04, 0xf1, 0x92, 0x24, 0x98, 0x20, 0xbc, 0x24,
|
||||
0x25, 0x09, 0x2e, 0x0e, 0xb0, 0xca, 0x82, 0x9c, 0x4a, 0x90, 0x4c, 0x19, 0x4c, 0x5d, 0x99, 0x92,
|
||||
0x36, 0x17, 0xaf, 0x73, 0x7e, 0x5e, 0x72, 0x62, 0x09, 0x86, 0x31, 0x9c, 0x28, 0xc6, 0x70, 0x82,
|
||||
0x8c, 0x91, 0xe6, 0xe2, 0x86, 0x29, 0x46, 0x31, 0x09, 0x28, 0x59, 0x66, 0x14, 0xc3, 0xc5, 0xec,
|
||||
0x98, 0x92, 0x22, 0xa4, 0xca, 0xc5, 0x0c, 0xb4, 0x4a, 0x88, 0x4f, 0xaf, 0x20, 0x49, 0x0f, 0xe1,
|
||||
0x3a, 0x29, 0x1e, 0x38, 0x1f, 0xa8, 0x53, 0x89, 0x41, 0x48, 0x8f, 0x8b, 0x0d, 0x62, 0x94, 0x90,
|
||||
0x20, 0x48, 0x06, 0xc5, 0x0d, 0x52, 0xfc, 0xc8, 0x42, 0x60, 0xf5, 0x49, 0x6c, 0x60, 0x6f, 0x1b,
|
||||
0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x8b, 0x2c, 0x12, 0xb4, 0x06, 0x01, 0x00, 0x00,
|
||||
0x25, 0x2d, 0x2e, 0x0e, 0xb0, 0xca, 0x82, 0x9c, 0x4a, 0x90, 0x4c, 0x19, 0x4c, 0x5d, 0x99, 0x90,
|
||||
0x00, 0x17, 0x73, 0x6a, 0x51, 0x11, 0x58, 0x25, 0x67, 0x10, 0x88, 0xa9, 0xa4, 0xcd, 0xc5, 0xeb,
|
||||
0x9c, 0x9f, 0x97, 0x9c, 0x58, 0x82, 0x61, 0x30, 0x27, 0x8a, 0xc1, 0x9c, 0x20, 0x83, 0x75, 0xb9,
|
||||
0xb8, 0x61, 0x8a, 0x51, 0xcc, 0xe6, 0xc4, 0x6a, 0xb6, 0x51, 0x0c, 0x17, 0xb3, 0x63, 0x4a, 0x8a,
|
||||
0x90, 0x2a, 0x17, 0x33, 0xd0, 0x39, 0x42, 0x7c, 0x7a, 0x05, 0x49, 0x7a, 0x08, 0x1f, 0x48, 0xf1,
|
||||
0xc0, 0xf9, 0x40, 0xb3, 0x94, 0x18, 0x84, 0xf4, 0xb8, 0xd8, 0x20, 0x86, 0x0b, 0x09, 0x82, 0x64,
|
||||
0x50, 0x5c, 0x25, 0xc5, 0x8f, 0x2c, 0x04, 0x56, 0x9f, 0xc4, 0x06, 0x0e, 0x1a, 0x63, 0x40, 0x00,
|
||||
0x00, 0x00, 0xff, 0xff, 0xdc, 0x37, 0x81, 0x99, 0x2a, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ message SumRequest {
|
||||
// The sum response contains the result of the calculation.
|
||||
message SumReply {
|
||||
int64 v = 1;
|
||||
string err = 2;
|
||||
}
|
||||
|
||||
// The Concat request contains two parameters.
|
||||
@ -31,4 +32,5 @@ message ConcatRequest {
|
||||
// The Concat response contains the result of the concatenation.
|
||||
message ConcatReply {
|
||||
string v = 1;
|
||||
string err = 2;
|
||||
}
|
||||
|
@ -19,17 +19,46 @@ type Service interface {
|
||||
Concat(ctx context.Context, a, b string) (string, error)
|
||||
}
|
||||
|
||||
// Business-domain errors like these may be served in two ways: returned
|
||||
// directly by endpoints, or bundled into the response struct. Both methods can
|
||||
// be made to work, but errors returned directly by endpoints are counted by
|
||||
// middlewares that check errors, like circuit breakers.
|
||||
//
|
||||
// If you don't want that behavior -- and you probably don't -- then it's better
|
||||
// to bundle errors into the response struct.
|
||||
|
||||
var (
|
||||
// ErrTwoZeroes is an arbitrary business rule for the Add method.
|
||||
ErrTwoZeroes = errors.New("can't sum two zeroes")
|
||||
|
||||
// ErrIntOverflow protects the Add method.
|
||||
// ErrIntOverflow protects the Add method. We've decided that this error
|
||||
// indicates a misbehaving service and should count against e.g. circuit
|
||||
// breakers. So, we return it directly in endpoints, to illustrate the
|
||||
// difference. In a real service, this probably wouldn't be the case.
|
||||
ErrIntOverflow = errors.New("integer overflow")
|
||||
|
||||
// ErrMaxSizeExceeded protects the Concat method.
|
||||
ErrMaxSizeExceeded = errors.New("result exceeds maximum size")
|
||||
)
|
||||
|
||||
// These annoying helper functions are required to translate Go error types to
|
||||
// and from strings, which is the type we use in our IDLs to represent errors.
|
||||
// There is special casing to treat empty strings as nil errors.
|
||||
|
||||
func str2err(s string) error {
|
||||
if s == "" {
|
||||
return nil
|
||||
}
|
||||
return errors.New(s)
|
||||
}
|
||||
|
||||
func err2str(err error) string {
|
||||
if err == nil {
|
||||
return ""
|
||||
}
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
// NewBasicService returns a naïve, stateless implementation of Service.
|
||||
func NewBasicService() Service {
|
||||
return basicService{}
|
||||
|
@ -1,9 +1,11 @@
|
||||
struct SumReply {
|
||||
1: i64 value
|
||||
2: string err
|
||||
}
|
||||
|
||||
struct ConcatReply {
|
||||
1: string value
|
||||
2: string err
|
||||
}
|
||||
|
||||
service AddService {
|
||||
|
@ -18,8 +18,10 @@ var GoUnusedProtection__ int
|
||||
|
||||
// Attributes:
|
||||
// - Value
|
||||
// - Err
|
||||
type SumReply struct {
|
||||
Value int64 `thrift:"value,1" json:"value"`
|
||||
Value int64 `thrift:"value,1" json:"value"`
|
||||
Err string `thrift:"err,2" json:"err"`
|
||||
}
|
||||
|
||||
func NewSumReply() *SumReply {
|
||||
@ -29,6 +31,10 @@ func NewSumReply() *SumReply {
|
||||
func (p *SumReply) GetValue() int64 {
|
||||
return p.Value
|
||||
}
|
||||
|
||||
func (p *SumReply) GetErr() string {
|
||||
return p.Err
|
||||
}
|
||||
func (p *SumReply) Read(iprot thrift.TProtocol) error {
|
||||
if _, err := iprot.ReadStructBegin(); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
|
||||
@ -47,6 +53,10 @@ func (p *SumReply) Read(iprot thrift.TProtocol) error {
|
||||
if err := p.readField1(iprot); err != nil {
|
||||
return err
|
||||
}
|
||||
case 2:
|
||||
if err := p.readField2(iprot); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if err := iprot.Skip(fieldTypeId); err != nil {
|
||||
return err
|
||||
@ -71,6 +81,15 @@ func (p *SumReply) readField1(iprot thrift.TProtocol) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *SumReply) readField2(iprot thrift.TProtocol) error {
|
||||
if v, err := iprot.ReadString(); err != nil {
|
||||
return thrift.PrependError("error reading field 2: ", err)
|
||||
} else {
|
||||
p.Err = v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *SumReply) Write(oprot thrift.TProtocol) error {
|
||||
if err := oprot.WriteStructBegin("SumReply"); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err)
|
||||
@ -78,6 +97,9 @@ func (p *SumReply) Write(oprot thrift.TProtocol) error {
|
||||
if err := p.writeField1(oprot); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.writeField2(oprot); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := oprot.WriteFieldStop(); err != nil {
|
||||
return thrift.PrependError("write field stop error: ", err)
|
||||
}
|
||||
@ -100,6 +122,19 @@ func (p *SumReply) writeField1(oprot thrift.TProtocol) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *SumReply) writeField2(oprot thrift.TProtocol) (err error) {
|
||||
if err := oprot.WriteFieldBegin("err", thrift.STRING, 2); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:err: ", p), err)
|
||||
}
|
||||
if err := oprot.WriteString(string(p.Err)); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T.err (2) field write error: ", p), err)
|
||||
}
|
||||
if err := oprot.WriteFieldEnd(); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field end error 2:err: ", p), err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *SumReply) String() string {
|
||||
if p == nil {
|
||||
return "<nil>"
|
||||
@ -109,8 +144,10 @@ func (p *SumReply) String() string {
|
||||
|
||||
// Attributes:
|
||||
// - Value
|
||||
// - Err
|
||||
type ConcatReply struct {
|
||||
Value string `thrift:"value,1" json:"value"`
|
||||
Err string `thrift:"err,2" json:"err"`
|
||||
}
|
||||
|
||||
func NewConcatReply() *ConcatReply {
|
||||
@ -120,6 +157,10 @@ func NewConcatReply() *ConcatReply {
|
||||
func (p *ConcatReply) GetValue() string {
|
||||
return p.Value
|
||||
}
|
||||
|
||||
func (p *ConcatReply) GetErr() string {
|
||||
return p.Err
|
||||
}
|
||||
func (p *ConcatReply) Read(iprot thrift.TProtocol) error {
|
||||
if _, err := iprot.ReadStructBegin(); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T read error: ", p), err)
|
||||
@ -138,6 +179,10 @@ func (p *ConcatReply) Read(iprot thrift.TProtocol) error {
|
||||
if err := p.readField1(iprot); err != nil {
|
||||
return err
|
||||
}
|
||||
case 2:
|
||||
if err := p.readField2(iprot); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if err := iprot.Skip(fieldTypeId); err != nil {
|
||||
return err
|
||||
@ -162,6 +207,15 @@ func (p *ConcatReply) readField1(iprot thrift.TProtocol) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ConcatReply) readField2(iprot thrift.TProtocol) error {
|
||||
if v, err := iprot.ReadString(); err != nil {
|
||||
return thrift.PrependError("error reading field 2: ", err)
|
||||
} else {
|
||||
p.Err = v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ConcatReply) Write(oprot thrift.TProtocol) error {
|
||||
if err := oprot.WriteStructBegin("ConcatReply"); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err)
|
||||
@ -169,6 +223,9 @@ func (p *ConcatReply) Write(oprot thrift.TProtocol) error {
|
||||
if err := p.writeField1(oprot); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.writeField2(oprot); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := oprot.WriteFieldStop(); err != nil {
|
||||
return thrift.PrependError("write field stop error: ", err)
|
||||
}
|
||||
@ -191,6 +248,19 @@ func (p *ConcatReply) writeField1(oprot thrift.TProtocol) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *ConcatReply) writeField2(oprot thrift.TProtocol) (err error) {
|
||||
if err := oprot.WriteFieldBegin("err", thrift.STRING, 2); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field begin error 2:err: ", p), err)
|
||||
}
|
||||
if err := oprot.WriteString(string(p.Err)); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T.err (2) field write error: ", p), err)
|
||||
}
|
||||
if err := oprot.WriteFieldEnd(); err != nil {
|
||||
return thrift.PrependError(fmt.Sprintf("%T write field end error 2:err: ", p), err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *ConcatReply) String() string {
|
||||
if p == nil {
|
||||
return "<nil>"
|
||||
|
@ -76,7 +76,7 @@ func DecodeGRPCConcatRequest(_ context.Context, grpcReq interface{}) (interface{
|
||||
// gRPC sum reply to a user-domain sum response. Primarily useful in a client.
|
||||
func DecodeGRPCSumResponse(_ context.Context, grpcReply interface{}) (interface{}, error) {
|
||||
reply := grpcReply.(*pb.SumReply)
|
||||
return sumResponse{V: int(reply.V)}, nil
|
||||
return sumResponse{V: int(reply.V), Err: str2err(reply.Err)}, nil
|
||||
}
|
||||
|
||||
// DecodeGRPCConcatResponse is a transport/grpc.DecodeResponseFunc that converts
|
||||
@ -84,14 +84,14 @@ func DecodeGRPCSumResponse(_ context.Context, grpcReply interface{}) (interface{
|
||||
// client.
|
||||
func DecodeGRPCConcatResponse(_ context.Context, grpcReply interface{}) (interface{}, error) {
|
||||
reply := grpcReply.(*pb.ConcatReply)
|
||||
return concatResponse{V: reply.V}, nil
|
||||
return concatResponse{V: reply.V, Err: str2err(reply.Err)}, nil
|
||||
}
|
||||
|
||||
// EncodeGRPCSumResponse is a transport/grpc.EncodeResponseFunc that converts a
|
||||
// user-domain sum response to a gRPC sum reply. Primarily useful in a server.
|
||||
func EncodeGRPCSumResponse(_ context.Context, response interface{}) (interface{}, error) {
|
||||
resp := response.(sumResponse)
|
||||
return &pb.SumReply{V: int64(resp.V)}, nil
|
||||
return &pb.SumReply{V: int64(resp.V), Err: err2str(resp.Err)}, nil
|
||||
}
|
||||
|
||||
// EncodeGRPCConcatResponse is a transport/grpc.EncodeResponseFunc that converts
|
||||
@ -99,7 +99,7 @@ func EncodeGRPCSumResponse(_ context.Context, response interface{}) (interface{}
|
||||
// server.
|
||||
func EncodeGRPCConcatResponse(_ context.Context, response interface{}) (interface{}, error) {
|
||||
resp := response.(concatResponse)
|
||||
return &pb.ConcatReply{V: resp.V}, nil
|
||||
return &pb.ConcatReply{V: resp.V, Err: err2str(resp.Err)}, nil
|
||||
}
|
||||
|
||||
// EncodeGRPCSumRequest is a transport/grpc.EncodeRequestFunc that converts a
|
||||
|
@ -35,7 +35,7 @@ func (s *thriftServer) Sum(a int64, b int64) (*thriftadd.SumReply, error) {
|
||||
return nil, err
|
||||
}
|
||||
resp := response.(sumResponse)
|
||||
return &thriftadd.SumReply{Value: int64(resp.V)}, nil
|
||||
return &thriftadd.SumReply{Value: int64(resp.V), Err: err2str(resp.Err)}, nil
|
||||
}
|
||||
|
||||
func (s *thriftServer) Concat(a string, b string) (*thriftadd.ConcatReply, error) {
|
||||
@ -45,7 +45,7 @@ func (s *thriftServer) Concat(a string, b string) (*thriftadd.ConcatReply, error
|
||||
return nil, err
|
||||
}
|
||||
resp := response.(concatResponse)
|
||||
return &thriftadd.ConcatReply{Value: resp.V}, nil
|
||||
return &thriftadd.ConcatReply{Value: resp.V, Err: err2str(resp.Err)}, nil
|
||||
}
|
||||
|
||||
// MakeThriftSumEndpoint returns an endpoint that invokes the passed Thrift client.
|
||||
@ -54,10 +54,10 @@ func MakeThriftSumEndpoint(client *thriftadd.AddServiceClient) endpoint.Endpoint
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(sumRequest)
|
||||
reply, err := client.Sum(int64(req.A), int64(req.B))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if err == ErrIntOverflow {
|
||||
return nil, err // special case; see comment on ErrIntOverflow
|
||||
}
|
||||
return sumResponse{V: int(reply.Value)}, nil
|
||||
return sumResponse{V: int(reply.Value), Err: err}, nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,9 +68,6 @@ func MakeThriftConcatEndpoint(client *thriftadd.AddServiceClient) endpoint.Endpo
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(concatRequest)
|
||||
reply, err := client.Concat(req.A, req.B)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return concatResponse{V: reply.Value}, nil
|
||||
return concatResponse{V: reply.Value, Err: err}, nil
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user