1
0
mirror of https://github.com/go-kit/kit.git synced 2025-07-17 01:12:38 +02:00

examples/addsvc: more sophisticated error encoding

This commit is contained in:
Peter Bourgon
2016-06-07 13:21:21 +02:00
parent 0db02c6772
commit 94228a75e6
8 changed files with 144 additions and 36 deletions

View File

@ -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,
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,
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
}

View File

@ -48,6 +48,7 @@ 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"`
Err string `protobuf:"bytes,2,opt,name=err" json:"err,omitempty"`
}
func (m *SumReply) Reset() { *m = SumReply{} }
@ -69,6 +70,7 @@ 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"`
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,
}

View File

@ -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;
}

View File

@ -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{}

View File

@ -1,9 +1,11 @@
struct SumReply {
1: i64 value
2: string err
}
struct ConcatReply {
1: string value
2: string err
}
service AddService {

View File

@ -18,8 +18,10 @@ var GoUnusedProtection__ int
// Attributes:
// - Value
// - Err
type SumReply struct {
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>"

View File

@ -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

View File

@ -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
}
}