Codebase list golang-github-go-kit-kit / 890b7c3
Merge pull request #407 from go-kit/issue-389 Remove error wrapping from package transport Peter Bourgon authored 7 years ago GitHub committed 7 years ago
9 changed file(s) with 21 addition(s) and 154 deletion(s). Raw diff Collapse all Expand all
4646 code := http.StatusInternalServerError
4747 msg := err.Error()
4848
49 if e, ok := err.(httptransport.Error); ok {
50 msg = e.Err.Error()
51 switch e.Domain {
52 case httptransport.DomainDecode:
53 code = http.StatusBadRequest
54
55 case httptransport.DomainDo:
56 switch e.Err {
57 case ErrTwoZeroes, ErrMaxSizeExceeded, ErrIntOverflow:
58 code = http.StatusBadRequest
59 }
60 }
49 switch err {
50 case ErrTwoZeroes, ErrMaxSizeExceeded, ErrIntOverflow:
51 code = http.StatusBadRequest
6152 }
6253
6354 w.WriteHeader(code)
404404 case ErrAlreadyExists, ErrInconsistentIDs:
405405 return http.StatusBadRequest
406406 default:
407 if e, ok := err.(httptransport.Error); ok {
408 switch e.Domain {
409 case httptransport.DomainDecode:
410 return http.StatusBadRequest
411 case httptransport.DomainDo:
412 return http.StatusServiceUnavailable
413 default:
414 return http.StatusInternalServerError
415 }
416 }
417407 return http.StatusInternalServerError
418408 }
419409 }
7878
7979 req, err := c.enc(ctx, request)
8080 if err != nil {
81 return nil, fmt.Errorf("Encode: %v", err)
81 return nil, err
8282 }
8383
8484 md := &metadata.MD{}
8989
9090 grpcReply := reflect.New(c.grpcReply).Interface()
9191 if err = grpc.Invoke(ctx, c.method, req, grpcReply, c.client); err != nil {
92 return nil, fmt.Errorf("Invoke: %v", err)
92 return nil, err
9393 }
9494
9595 response, err := c.dec(ctx, grpcReply)
9696 if err != nil {
97 return nil, fmt.Errorf("Decode: %v", err)
97 return nil, err
9898 }
9999 return response, nil
100100 }
9191 request, err := s.dec(grpcCtx, req)
9292 if err != nil {
9393 s.logger.Log("err", err)
94 return grpcCtx, nil, BadRequestError{err}
94 return grpcCtx, nil, err
9595 }
9696
9797 response, err := s.e(ctx, request)
115115
116116 return grpcCtx, grpcResp, nil
117117 }
118
119 // BadRequestError is an error in decoding the request.
120 type BadRequestError struct {
121 Err error
122 }
123
124 // Error implements the error interface.
125 func (err BadRequestError) Error() string {
126 return err.Err.Error()
127 }
8181
8282 req, err := http.NewRequest(c.method, c.tgt.String(), nil)
8383 if err != nil {
84 return nil, Error{Domain: DomainNewRequest, Err: err}
84 return nil, err
8585 }
8686
8787 if err = c.enc(ctx, req, request); err != nil {
88 return nil, Error{Domain: DomainEncode, Err: err}
88 return nil, err
8989 }
9090
9191 for _, f := range c.before {
9494
9595 resp, err := ctxhttp.Do(ctx, c.client, req)
9696 if err != nil {
97 return nil, Error{Domain: DomainDo, Err: err}
97 return nil, err
9898 }
9999 if !c.bufferedStream {
100100 defer resp.Body.Close()
106106
107107 response, err := c.dec(ctx, resp)
108108 if err != nil {
109 return nil, Error{Domain: DomainDecode, Err: err}
109 return nil, err
110110 }
111111
112112 return response, nil
+0
-33
transport/http/err.go less more
0 package http
1
2 import (
3 "fmt"
4 )
5
6 const (
7 // DomainNewRequest is an error during request generation.
8 DomainNewRequest = "NewRequest"
9
10 // DomainEncode is an error during request or response encoding.
11 DomainEncode = "Encode"
12
13 // DomainDo is an error during the execution phase of the request.
14 DomainDo = "Do"
15
16 // DomainDecode is an error during request or response decoding.
17 DomainDecode = "Decode"
18 )
19
20 // Error is an error that occurred at some phase within the transport.
21 type Error struct {
22 // Domain is the phase in which the error was generated.
23 Domain string
24
25 // Err is the concrete error.
26 Err error
27 }
28
29 // Error implements the error interface.
30 func (e Error) Error() string {
31 return fmt.Sprintf("%s: %s", e.Domain, e.Err)
32 }
+0
-56
transport/http/err_test.go less more
0 package http_test
1
2 import (
3 "errors"
4 "fmt"
5 "net/http"
6 "net/url"
7 "testing"
8
9 "golang.org/x/net/context"
10
11 httptransport "github.com/go-kit/kit/transport/http"
12 )
13
14 func TestClientEndpointEncodeError(t *testing.T) {
15 var (
16 sampleErr = errors.New("Oh no, an error")
17 enc = func(context.Context, *http.Request, interface{}) error { return sampleErr }
18 dec = func(context.Context, *http.Response) (interface{}, error) { return nil, nil }
19 )
20
21 u := &url.URL{
22 Scheme: "https",
23 Host: "localhost",
24 Path: "/does/not/matter",
25 }
26
27 c := httptransport.NewClient(
28 "GET",
29 u,
30 enc,
31 dec,
32 )
33
34 _, err := c.Endpoint()(context.Background(), nil)
35 if err == nil {
36 t.Fatal("err == nil")
37 }
38
39 e, ok := err.(httptransport.Error)
40 if !ok {
41 t.Fatal("err is not of type github.com/go-kit/kit/transport/http.Error")
42 }
43
44 if want, have := sampleErr, e.Err; want != have {
45 t.Fatalf("want %v, have %v", want, have)
46 }
47 }
48
49 func ExampleErrorOutput() {
50 sampleErr := errors.New("oh no, an error")
51 err := httptransport.Error{Domain: httptransport.DomainDo, Err: sampleErr}
52 fmt.Println(err)
53 // Output:
54 // Do: oh no, an error
55 }
8484 request, err := s.dec(ctx, r)
8585 if err != nil {
8686 s.logger.Log("err", err)
87 s.errorEncoder(ctx, Error{Domain: DomainDecode, Err: err}, w)
87 s.errorEncoder(ctx, err, w)
8888 return
8989 }
9090
9191 response, err := s.e(ctx, request)
9292 if err != nil {
9393 s.logger.Log("err", err)
94 s.errorEncoder(ctx, Error{Domain: DomainDo, Err: err}, w)
94 s.errorEncoder(ctx, err, w)
9595 return
9696 }
9797
101101
102102 if err := s.enc(ctx, w, response); err != nil {
103103 s.logger.Log("err", err)
104 s.errorEncoder(ctx, Error{Domain: DomainEncode, Err: err}, w)
104 s.errorEncoder(ctx, err, w)
105105 return
106106 }
107107 }
108108
109109 // ErrorEncoder is responsible for encoding an error to the ResponseWriter.
110 //
111 // In the server implementation, only kit/transport/http.Error values are ever
112 // passed to this function, so you might be tempted to have this function take
113 // one of those directly. But, users are encouraged to use custom ErrorEncoders
114 // to encode all HTTP errors to their clients, and so may want to pass and check
115 // for their own error types. See the example shipping/handling service.
110 // Users are encouraged to use custom ErrorEncoders to encode HTTP errors to
111 // their clients, and will likely want to pass and check for their own error
112 // types. See the example shipping/handling service.
116113 type ErrorEncoder func(ctx context.Context, err error, w http.ResponseWriter)
117114
118115 func defaultErrorEncoder(_ context.Context, err error, w http.ResponseWriter) {
119 switch e := err.(type) {
120 case Error:
121 switch e.Domain {
122 case DomainDecode:
123 http.Error(w, err.Error(), http.StatusBadRequest)
124 case DomainDo:
125 http.Error(w, err.Error(), http.StatusServiceUnavailable) // too aggressive?
126 default:
127 http.Error(w, err.Error(), http.StatusInternalServerError)
128 }
129 default:
130 http.Error(w, err.Error(), http.StatusInternalServerError)
131 }
116 http.Error(w, err.Error(), http.StatusInternalServerError)
132117 }
2121 server := httptest.NewServer(handler)
2222 defer server.Close()
2323 resp, _ := http.Get(server.URL)
24 if want, have := http.StatusBadRequest, resp.StatusCode; want != have {
24 if want, have := http.StatusInternalServerError, resp.StatusCode; want != have {
2525 t.Errorf("want %d, have %d", want, have)
2626 }
2727 }
3636 server := httptest.NewServer(handler)
3737 defer server.Close()
3838 resp, _ := http.Get(server.URL)
39 if want, have := http.StatusServiceUnavailable, resp.StatusCode; want != have {
39 if want, have := http.StatusInternalServerError, resp.StatusCode; want != have {
4040 t.Errorf("want %d, have %d", want, have)
4141 }
4242 }
5959 func TestServerErrorEncoder(t *testing.T) {
6060 errTeapot := errors.New("teapot")
6161 code := func(err error) int {
62 if e, ok := err.(httptransport.Error); ok && e.Err == errTeapot {
62 if err == errTeapot {
6363 return http.StatusTeapot
6464 }
6565 return http.StatusInternalServerError