Merge pull request #125 from go-kit/transport-http-constructor
transport/http: Constructors
Peter Bourgon
8 years ago
150 | 150 | ctx := context.Background() |
151 | 151 | svc := stringService{} |
152 | 152 | |
153 | uppercaseHandler := httptransport.Server{ | |
154 | Context: ctx, | |
155 | Endpoint: makeUppercaseEndpoint(svc), | |
156 | DecodeRequestFunc: decodeUppercaseRequest, | |
157 | EncodeResponseFunc: encodeResponse, | |
158 | } | |
159 | ||
160 | countHandler := httptransport.Server{ | |
161 | Context: ctx, | |
162 | Endpoint: makeCountEndpoint(svc), | |
163 | DecodeRequestFunc: decodeCountRequest, | |
164 | EncodeResponseFunc: encodeResponse, | |
165 | } | |
153 | uppercaseHandler := httptransport.NewServer( | |
154 | ctx, | |
155 | makeUppercaseEndpoint(svc), | |
156 | decodeUppercaseRequest, | |
157 | encodeResponse, | |
158 | ) | |
159 | ||
160 | countHandler := httptransport.NewServer( | |
161 | ctx, | |
162 | makeCountEndpoint(svc), | |
163 | decodeCountRequest, | |
164 | encodeResponse, | |
165 | ) | |
166 | 166 | |
167 | 167 | http.Handle("/uppercase", uppercaseHandler) |
168 | 168 | http.Handle("/count", countHandler) |
256 | 256 | count = makeCountEndpoint(svc) |
257 | 257 | count = loggingMiddleware(log.NewContext(logger).With("method", "count"))(count) |
258 | 258 | |
259 | uppercaseHandler := httptransport.Server{ | |
260 | Endpoint: uppercase, | |
259 | uppercaseHandler := httptransport.Server( | |
261 | 260 | // ... |
262 | } | |
263 | ||
264 | countHandler := httptransport.Server{ | |
265 | Endpoint: count, | |
261 | uppercase, | |
266 | 262 | // ... |
267 | } | |
263 | ) | |
264 | ||
265 | countHandler := httptransport.Server( | |
266 | // ... | |
267 | count, | |
268 | // ... | |
269 | ) | |
268 | 270 | ``` |
269 | 271 | |
270 | 272 | It turns out that this technique is useful for a lot more than just logging. |
329 | 331 | svc := stringService{} |
330 | 332 | svc = loggingMiddleware{logger, svc} |
331 | 333 | |
332 | uppercaseHandler := httptransport.Server{ | |
333 | Endpoint: makeUppercaseEndpoint(svc), | |
334 | // ... | |
335 | } | |
336 | ||
337 | countHandler := httptransport.Server{ | |
338 | Endpoint: makeCountEndpoint(svc), | |
339 | // ... | |
340 | } | |
334 | uppercaseHandler := httptransport.NewServer( | |
335 | // ... | |
336 | makeUppercaseEndpoint(svc), | |
337 | // ... | |
338 | ) | |
339 | ||
340 | countHandler := httptransport.NewServer( | |
341 | // ... | |
342 | makeCountEndpoint(svc), | |
343 | // ... | |
344 | ) | |
341 | 345 | } |
342 | 346 | ``` |
343 | 347 | |
415 | 419 | svc = loggingMiddleware{logger, svc} |
416 | 420 | svc = instrumentingMiddleware{requestCount, requestLatency, countResult, svc} |
417 | 421 | |
418 | uppercaseHandler := httptransport.Server{ | |
419 | Endpoint: makeUppercaseEndpoint(svc), | |
420 | // ... | |
421 | } | |
422 | ||
423 | countHandler := httptransport.Server{ | |
424 | Endpoint: makeCountEndpoint(svc), | |
425 | // ... | |
426 | } | |
422 | uppercaseHandler := httptransport.NewServer( | |
423 | // ... | |
424 | makeUppercaseEndpoint(svc), | |
425 | // ... | |
426 | ) | |
427 | ||
428 | countHandler := httptransport.NewServer( | |
429 | // ... | |
430 | makeCountEndpoint(svc), | |
431 | // ... | |
432 | ) | |
427 | 433 | |
428 | 434 | http.Handle("/metrics", stdprometheus.Handler()) |
429 | 435 | } |
509 | 515 | } |
510 | 516 | |
511 | 517 | func makeUppercaseEndpoint(ctx context.Context, proxyURL string) endpoint.Endpoint { |
512 | return (httptransport.Client{ | |
513 | Client: http.DefaultClient, | |
514 | Method: "GET", | |
515 | URL: mustParseURL(proxyURL), | |
516 | Context: ctx, | |
517 | EncodeFunc: encodeUppercaseRequest, | |
518 | DecodeFunc: decodeUppercaseResponse, | |
519 | }).Endpoint() | |
518 | return httptransport.NewClient( | |
519 | "GET", | |
520 | mustParseURL(proxyURL), | |
521 | encodeUppercaseRequest, | |
522 | decodeUppercaseResponse, | |
523 | ).Endpoint() | |
520 | 524 | } |
521 | 525 | ``` |
522 | 526 |
28 | 28 | return client{ |
29 | 29 | Context: ctx, |
30 | 30 | Logger: logger, |
31 | sum: (httptransport.Client{ | |
32 | Client: c, | |
33 | Method: "GET", | |
34 | URL: sumURL, | |
35 | EncodeRequestFunc: server.EncodeSumRequest, | |
36 | DecodeResponseFunc: server.DecodeSumResponse, | |
37 | }).Endpoint(), | |
38 | concat: (httptransport.Client{ | |
39 | Client: c, | |
40 | Method: "GET", | |
41 | URL: concatURL, | |
42 | EncodeRequestFunc: server.EncodeConcatRequest, | |
43 | DecodeResponseFunc: server.DecodeConcatResponse, | |
44 | }).Endpoint(), | |
31 | sum: httptransport.NewClient( | |
32 | "GET", | |
33 | sumURL, | |
34 | server.EncodeSumRequest, | |
35 | server.DecodeSumResponse, | |
36 | ).Endpoint(), | |
37 | concat: httptransport.NewClient( | |
38 | "GET", | |
39 | concatURL, | |
40 | server.EncodeConcatRequest, | |
41 | server.DecodeConcatResponse, | |
42 | ).Endpoint(), | |
45 | 43 | } |
46 | 44 | } |
47 | 45 |
138 | 138 | |
139 | 139 | sum = makeSumEndpoint(svc) |
140 | 140 | sum = zipkin.AnnotateServer(newSumSpan, collector)(sum) |
141 | mux.Handle("/sum", httptransport.Server{ | |
142 | Context: root, | |
143 | Endpoint: sum, | |
144 | DecodeRequestFunc: server.DecodeSumRequest, | |
145 | EncodeResponseFunc: server.EncodeSumResponse, | |
146 | Before: []httptransport.RequestFunc{traceSum}, | |
147 | After: []httptransport.ResponseFunc{}, | |
148 | Logger: transportLogger, | |
149 | }) | |
141 | mux.Handle("/sum", httptransport.NewServer( | |
142 | root, | |
143 | sum, | |
144 | server.DecodeSumRequest, | |
145 | server.EncodeSumResponse, | |
146 | httptransport.ServerBefore(traceSum), | |
147 | httptransport.ServerErrorLogger(transportLogger), | |
148 | )) | |
150 | 149 | |
151 | 150 | concat = makeConcatEndpoint(svc) |
152 | 151 | concat = zipkin.AnnotateServer(newConcatSpan, collector)(concat) |
153 | mux.Handle("/concat", httptransport.Server{ | |
154 | Context: root, | |
155 | Endpoint: concat, | |
156 | DecodeRequestFunc: server.DecodeConcatRequest, | |
157 | EncodeResponseFunc: server.EncodeConcatResponse, | |
158 | Before: []httptransport.RequestFunc{traceConcat}, | |
159 | After: []httptransport.ResponseFunc{}, | |
160 | Logger: transportLogger, | |
161 | }) | |
152 | mux.Handle("/concat", httptransport.NewServer( | |
153 | root, | |
154 | concat, | |
155 | server.DecodeConcatRequest, | |
156 | server.EncodeConcatResponse, | |
157 | httptransport.ServerBefore(traceConcat), | |
158 | httptransport.ServerErrorLogger(transportLogger), | |
159 | )) | |
162 | 160 | |
163 | 161 | _ = transportLogger.Log("addr", *httpAddr) |
164 | 162 | errc <- http.ListenAndServe(*httpAddr, mux) |
35 | 35 | ctx := context.Background() |
36 | 36 | svc := stringService{} |
37 | 37 | |
38 | uppercaseHandler := httptransport.Server{ | |
39 | Context: ctx, | |
40 | Endpoint: makeUppercaseEndpoint(svc), | |
41 | DecodeRequestFunc: decodeUppercaseRequest, | |
42 | EncodeResponseFunc: encodeResponse, | |
43 | } | |
38 | uppercaseHandler := httptransport.NewServer( | |
39 | ctx, | |
40 | makeUppercaseEndpoint(svc), | |
41 | decodeUppercaseRequest, | |
42 | encodeResponse, | |
43 | ) | |
44 | 44 | |
45 | countHandler := httptransport.Server{ | |
46 | Context: ctx, | |
47 | Endpoint: makeCountEndpoint(svc), | |
48 | DecodeRequestFunc: decodeCountRequest, | |
49 | EncodeResponseFunc: encodeResponse, | |
50 | } | |
45 | countHandler := httptransport.NewServer( | |
46 | ctx, | |
47 | makeCountEndpoint(svc), | |
48 | decodeCountRequest, | |
49 | encodeResponse, | |
50 | ) | |
51 | 51 | |
52 | 52 | http.Handle("/uppercase", uppercaseHandler) |
53 | 53 | http.Handle("/count", countHandler) |
42 | 42 | svc = loggingMiddleware{logger, svc} |
43 | 43 | svc = instrumentingMiddleware{requestCount, requestLatency, countResult, svc} |
44 | 44 | |
45 | uppercaseHandler := httptransport.Server{ | |
46 | Context: ctx, | |
47 | Endpoint: makeUppercaseEndpoint(svc), | |
48 | DecodeRequestFunc: decodeUppercaseRequest, | |
49 | EncodeResponseFunc: encodeResponse, | |
50 | } | |
45 | uppercaseHandler := httptransport.NewServer( | |
46 | ctx, | |
47 | makeUppercaseEndpoint(svc), | |
48 | decodeUppercaseRequest, | |
49 | encodeResponse, | |
50 | ) | |
51 | 51 | |
52 | countHandler := httptransport.Server{ | |
53 | Context: ctx, | |
54 | Endpoint: makeCountEndpoint(svc), | |
55 | DecodeRequestFunc: decodeCountRequest, | |
56 | EncodeResponseFunc: encodeResponse, | |
57 | } | |
52 | countHandler := httptransport.NewServer( | |
53 | ctx, | |
54 | makeCountEndpoint(svc), | |
55 | decodeCountRequest, | |
56 | encodeResponse, | |
57 | ) | |
58 | 58 | |
59 | 59 | http.Handle("/uppercase", uppercaseHandler) |
60 | 60 | http.Handle("/count", countHandler) |
53 | 53 | svc = loggingMiddleware(logger)(svc) |
54 | 54 | svc = instrumentingMiddleware(requestCount, requestLatency, countResult)(svc) |
55 | 55 | |
56 | uppercaseHandler := httptransport.Server{ | |
57 | Context: ctx, | |
58 | Endpoint: makeUppercaseEndpoint(svc), | |
59 | DecodeRequestFunc: decodeUppercaseRequest, | |
60 | EncodeResponseFunc: encodeResponse, | |
61 | } | |
62 | countHandler := httptransport.Server{ | |
63 | Context: ctx, | |
64 | Endpoint: makeCountEndpoint(svc), | |
65 | DecodeRequestFunc: decodeCountRequest, | |
66 | EncodeResponseFunc: encodeResponse, | |
67 | } | |
56 | uppercaseHandler := httptransport.NewServer( | |
57 | ctx, | |
58 | makeUppercaseEndpoint(svc), | |
59 | decodeUppercaseRequest, | |
60 | encodeResponse, | |
61 | ) | |
62 | countHandler := httptransport.NewServer( | |
63 | ctx, | |
64 | makeCountEndpoint(svc), | |
65 | decodeCountRequest, | |
66 | encodeResponse, | |
67 | ) | |
68 | 68 | |
69 | 69 | http.Handle("/uppercase", uppercaseHandler) |
70 | 70 | http.Handle("/count", countHandler) |
2 | 2 | import ( |
3 | 3 | "errors" |
4 | 4 | "fmt" |
5 | "net/http" | |
6 | 5 | "net/url" |
7 | 6 | "strings" |
8 | 7 | "time" |
84 | 83 | if u.Path == "" { |
85 | 84 | u.Path = "/uppercase" |
86 | 85 | } |
87 | return (httptransport.Client{ | |
88 | Client: http.DefaultClient, | |
89 | Method: "GET", | |
90 | URL: u, | |
91 | DecodeResponseFunc: decodeUppercaseResponse, | |
92 | EncodeRequestFunc: encodeRequest, | |
93 | }).Endpoint() | |
86 | return httptransport.NewClient( | |
87 | "GET", | |
88 | u, | |
89 | encodeRequest, | |
90 | decodeUppercaseResponse, | |
91 | ).Endpoint() | |
94 | 92 | } |
95 | 93 | |
96 | 94 | func split(s string) []string { |
11 | 11 | |
12 | 12 | // Client wraps a URL and provides a method that implements endpoint.Endpoint. |
13 | 13 | type Client struct { |
14 | // If client is nil, http.DefaultClient will be used. | |
15 | *http.Client | |
14 | client *http.Client | |
15 | method string | |
16 | tgt *url.URL | |
17 | enc EncodeRequestFunc | |
18 | dec DecodeResponseFunc | |
19 | before []RequestFunc | |
20 | } | |
16 | 21 | |
17 | // Method must be provided. | |
18 | Method string | |
22 | // NewClient returns a | |
23 | func NewClient(method string, tgt *url.URL, enc EncodeRequestFunc, dec DecodeResponseFunc, options ...ClientOption) *Client { | |
24 | c := &Client{ | |
25 | client: http.DefaultClient, | |
26 | method: method, | |
27 | tgt: tgt, | |
28 | enc: enc, | |
29 | dec: dec, | |
30 | before: []RequestFunc{}, | |
31 | } | |
32 | for _, option := range options { | |
33 | option(c) | |
34 | } | |
35 | return c | |
36 | } | |
19 | 37 | |
20 | // URL must be provided. | |
21 | URL *url.URL | |
38 | // ClientOption sets an optional parameter for clients. | |
39 | type ClientOption func(*Client) | |
22 | 40 | |
23 | // EncodeRequestFunc must be provided. The HTTP request passed to the | |
24 | // EncodeRequestFunc will have a nil body. | |
25 | EncodeRequestFunc | |
41 | // SetClient sets the underlying HTTP client used for requests. | |
42 | // By default, http.DefaultClient is used. | |
43 | func SetClient(client *http.Client) ClientOption { | |
44 | return func(c *Client) { c.client = client } | |
45 | } | |
26 | 46 | |
27 | // DecodeResponseFunc must be provided. | |
28 | DecodeResponseFunc | |
29 | ||
30 | // Before functions are executed on the outgoing request after it is | |
31 | // created, but before it's sent to the HTTP client. Clients have no After | |
32 | // ResponseFuncs, as they don't work with ResponseWriters. | |
33 | Before []RequestFunc | |
47 | // SetClientBefore sets the RequestFuncs that are applied to the outgoing HTTP | |
48 | // request before it's invoked. | |
49 | func SetClientBefore(before ...RequestFunc) ClientOption { | |
50 | return func(c *Client) { c.before = before } | |
34 | 51 | } |
35 | 52 | |
36 | 53 | // Endpoint returns a usable endpoint that will invoke the RPC specified by |
40 | 57 | ctx, cancel := context.WithCancel(ctx) |
41 | 58 | defer cancel() |
42 | 59 | |
43 | req, err := http.NewRequest(c.Method, c.URL.String(), nil) | |
60 | req, err := http.NewRequest(c.method, c.tgt.String(), nil) | |
44 | 61 | if err != nil { |
45 | 62 | return nil, fmt.Errorf("NewRequest: %v", err) |
46 | 63 | } |
47 | 64 | |
48 | if err = c.EncodeRequestFunc(req, request); err != nil { | |
65 | if err = c.enc(req, request); err != nil { | |
49 | 66 | return nil, fmt.Errorf("Encode: %v", err) |
50 | 67 | } |
51 | 68 | |
52 | for _, f := range c.Before { | |
69 | for _, f := range c.before { | |
53 | 70 | ctx = f(ctx, req) |
54 | 71 | } |
55 | 72 | |
56 | var resp *http.Response | |
57 | if c.Client != nil { | |
58 | resp, err = c.Client.Do(req) | |
59 | } else { | |
60 | resp, err = http.DefaultClient.Do(req) | |
61 | } | |
73 | resp, err := c.client.Do(req) | |
62 | 74 | if err != nil { |
63 | 75 | return nil, fmt.Errorf("Do: %v", err) |
64 | 76 | } |
65 | 77 | defer func() { _ = resp.Body.Close() }() |
66 | 78 | |
67 | response, err := c.DecodeResponseFunc(resp) | |
79 | response, err := c.dec(resp) | |
68 | 80 | if err != nil { |
69 | 81 | return nil, fmt.Errorf("Decode: %v", err) |
70 | 82 | } |
25 | 25 | w.WriteHeader(http.StatusOK) |
26 | 26 | })) |
27 | 27 | |
28 | client := httptransport.Client{ | |
29 | Method: "GET", | |
30 | URL: mustParse(server.URL), | |
31 | EncodeRequestFunc: encode, | |
32 | DecodeResponseFunc: decode, | |
33 | Before: []httptransport.RequestFunc{httptransport.SetRequestHeader(headerKey, headerVal)}, | |
34 | } | |
28 | client := httptransport.NewClient( | |
29 | "GET", | |
30 | mustParse(server.URL), | |
31 | encode, | |
32 | decode, | |
33 | httptransport.SetClientBefore(httptransport.SetRequestHeader(headerKey, headerVal)), | |
34 | ) | |
35 | 35 | |
36 | 36 | _, err := client.Endpoint()(context.Background(), struct{}{}) |
37 | 37 | if err != nil { |
10 | 10 | |
11 | 11 | // Server wraps an endpoint and implements http.Handler. |
12 | 12 | type Server struct { |
13 | // A background context must be provided. | |
14 | context.Context | |
13 | ctx context.Context | |
14 | e endpoint.Endpoint | |
15 | dec DecodeRequestFunc | |
16 | enc EncodeResponseFunc | |
17 | before []RequestFunc | |
18 | after []ResponseFunc | |
19 | errorEncoder func(w http.ResponseWriter, err error) | |
20 | logger log.Logger | |
21 | } | |
15 | 22 | |
16 | // The endpoint that will be invoked. | |
17 | endpoint.Endpoint | |
23 | // NewServer constructs a new server, which implements http.Server and wraps | |
24 | // the provided endpoint. | |
25 | func NewServer( | |
26 | ctx context.Context, | |
27 | e endpoint.Endpoint, | |
28 | dec DecodeRequestFunc, | |
29 | enc EncodeResponseFunc, | |
30 | options ...ServerOption, | |
31 | ) *Server { | |
32 | s := &Server{ | |
33 | ctx: ctx, | |
34 | e: e, | |
35 | dec: dec, | |
36 | enc: enc, | |
37 | errorEncoder: defaultErrorEncoder, | |
38 | logger: log.NewNopLogger(), | |
39 | } | |
40 | for _, option := range options { | |
41 | option(s) | |
42 | } | |
43 | return s | |
44 | } | |
18 | 45 | |
19 | // DecodeRequestFunc must be provided. | |
20 | DecodeRequestFunc | |
46 | // ServerOption sets an optional parameter for servers. | |
47 | type ServerOption func(*Server) | |
21 | 48 | |
22 | // EncodeResponseFunc must be provided. | |
23 | EncodeResponseFunc | |
49 | // ServerBefore functions are executed on the HTTP request object before the | |
50 | // request is decoded. | |
51 | func ServerBefore(before ...RequestFunc) ServerOption { | |
52 | return func(s *Server) { s.before = before } | |
53 | } | |
24 | 54 | |
25 | // Before functions are executed on the HTTP request object before the | |
26 | // request is decoded. | |
27 | Before []RequestFunc | |
55 | // ServerAfter functions are executed on the HTTP response writer after the | |
56 | // endpoint is invoked, but before anything is written to the client. | |
57 | func ServerAfter(after ...ResponseFunc) ServerOption { | |
58 | return func(s *Server) { s.after = after } | |
59 | } | |
28 | 60 | |
29 | // After functions are executed on the HTTP response writer after the | |
30 | // endpoint is invoked, but before anything is written to the client. | |
31 | After []ResponseFunc | |
61 | // ServerErrorEncoder is used to encode errors to the http.ResponseWriter | |
62 | // whenever they're encountered in the processing of a request. Clients can | |
63 | // use this to provide custom error formatting and response codes. By default, | |
64 | // errors will be written as plain text with an appropriate, if generic, | |
65 | // status code. | |
66 | func ServerErrorEncoder(f func(w http.ResponseWriter, err error)) ServerOption { | |
67 | return func(s *Server) { s.errorEncoder = f } | |
68 | } | |
32 | 69 | |
33 | // ErrorEncoder is used to encode errors to the http.ResponseWriter | |
34 | // whenever they're encountered in the processing of a request. Clients | |
35 | // can use this to provide custom error formatting and response codes. If | |
36 | // ErrorEncoder is nil, the error will be written as plain text with | |
37 | // an appropriate, if generic, status code. | |
38 | ErrorEncoder func(w http.ResponseWriter, err error) | |
39 | ||
40 | // Logger is used to log errors. | |
41 | Logger log.Logger | |
70 | // ServerErrorLogger is used to log non-terminal errors. By default, no errors | |
71 | // are logged. | |
72 | func ServerErrorLogger(logger log.Logger) ServerOption { | |
73 | return func(s *Server) { s.logger = logger } | |
42 | 74 | } |
43 | 75 | |
44 | 76 | // ServeHTTP implements http.Handler. |
45 | 77 | func (s Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { |
46 | if s.ErrorEncoder == nil { | |
47 | s.ErrorEncoder = defaultErrorEncoder | |
48 | } | |
49 | ||
50 | ctx, cancel := context.WithCancel(s.Context) | |
78 | ctx, cancel := context.WithCancel(s.ctx) | |
51 | 79 | defer cancel() |
52 | 80 | |
53 | for _, f := range s.Before { | |
81 | for _, f := range s.before { | |
54 | 82 | ctx = f(ctx, r) |
55 | 83 | } |
56 | 84 | |
57 | request, err := s.DecodeRequestFunc(r) | |
85 | request, err := s.dec(r) | |
58 | 86 | if err != nil { |
59 | _ = s.Logger.Log("err", err) | |
60 | s.ErrorEncoder(w, badRequestError{err}) | |
87 | _ = s.logger.Log("err", err) | |
88 | s.errorEncoder(w, badRequestError{err}) | |
61 | 89 | return |
62 | 90 | } |
63 | 91 | |
64 | response, err := s.Endpoint(ctx, request) | |
92 | response, err := s.e(ctx, request) | |
65 | 93 | if err != nil { |
66 | _ = s.Logger.Log("err", err) | |
67 | s.ErrorEncoder(w, err) | |
94 | _ = s.logger.Log("err", err) | |
95 | s.errorEncoder(w, err) | |
68 | 96 | return |
69 | 97 | } |
70 | 98 | |
71 | for _, f := range s.After { | |
99 | for _, f := range s.after { | |
72 | 100 | f(ctx, w) |
73 | 101 | } |
74 | 102 | |
75 | if err := s.EncodeResponseFunc(w, response); err != nil { | |
76 | _ = s.Logger.Log("err", err) | |
77 | s.ErrorEncoder(w, err) | |
103 | if err := s.enc(w, response); err != nil { | |
104 | _ = s.logger.Log("err", err) | |
105 | s.errorEncoder(w, err) | |
78 | 106 | return |
79 | 107 | } |
80 | 108 | } |
8 | 8 | |
9 | 9 | "golang.org/x/net/context" |
10 | 10 | |
11 | "github.com/go-kit/kit/log" | |
12 | 11 | httptransport "github.com/go-kit/kit/transport/http" |
13 | 12 | ) |
14 | 13 | |
15 | 14 | func TestServerBadDecode(t *testing.T) { |
16 | handler := httptransport.Server{ | |
17 | Context: context.Background(), | |
18 | Endpoint: func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil }, | |
19 | DecodeRequestFunc: func(*http.Request) (interface{}, error) { return struct{}{}, errors.New("dang") }, | |
20 | EncodeResponseFunc: func(http.ResponseWriter, interface{}) error { return nil }, | |
21 | Logger: log.NewNopLogger(), | |
22 | } | |
15 | handler := httptransport.NewServer( | |
16 | context.Background(), | |
17 | func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil }, | |
18 | func(*http.Request) (interface{}, error) { return struct{}{}, errors.New("dang") }, | |
19 | func(http.ResponseWriter, interface{}) error { return nil }, | |
20 | ) | |
23 | 21 | server := httptest.NewServer(handler) |
24 | 22 | defer server.Close() |
25 | 23 | resp, _ := http.Get(server.URL) |
29 | 27 | } |
30 | 28 | |
31 | 29 | func TestServerBadEndpoint(t *testing.T) { |
32 | handler := httptransport.Server{ | |
33 | Context: context.Background(), | |
34 | Endpoint: func(context.Context, interface{}) (interface{}, error) { return struct{}{}, errors.New("dang") }, | |
35 | DecodeRequestFunc: func(*http.Request) (interface{}, error) { return struct{}{}, nil }, | |
36 | EncodeResponseFunc: func(http.ResponseWriter, interface{}) error { return nil }, | |
37 | Logger: log.NewNopLogger(), | |
38 | } | |
30 | handler := httptransport.NewServer( | |
31 | context.Background(), | |
32 | func(context.Context, interface{}) (interface{}, error) { return struct{}{}, errors.New("dang") }, | |
33 | func(*http.Request) (interface{}, error) { return struct{}{}, nil }, | |
34 | func(http.ResponseWriter, interface{}) error { return nil }, | |
35 | ) | |
39 | 36 | server := httptest.NewServer(handler) |
40 | 37 | defer server.Close() |
41 | 38 | resp, _ := http.Get(server.URL) |
45 | 42 | } |
46 | 43 | |
47 | 44 | func TestServerBadEncode(t *testing.T) { |
48 | handler := httptransport.Server{ | |
49 | Context: context.Background(), | |
50 | Endpoint: func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil }, | |
51 | DecodeRequestFunc: func(*http.Request) (interface{}, error) { return struct{}{}, nil }, | |
52 | EncodeResponseFunc: func(http.ResponseWriter, interface{}) error { return errors.New("dang") }, | |
53 | Logger: log.NewNopLogger(), | |
54 | } | |
45 | handler := httptransport.NewServer( | |
46 | context.Background(), | |
47 | func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil }, | |
48 | func(*http.Request) (interface{}, error) { return struct{}{}, nil }, | |
49 | func(http.ResponseWriter, interface{}) error { return errors.New("dang") }, | |
50 | ) | |
55 | 51 | server := httptest.NewServer(handler) |
56 | 52 | defer server.Close() |
57 | 53 | resp, _ := http.Get(server.URL) |
68 | 64 | } |
69 | 65 | return http.StatusInternalServerError |
70 | 66 | } |
71 | handler := httptransport.Server{ | |
72 | Context: context.Background(), | |
73 | Endpoint: func(context.Context, interface{}) (interface{}, error) { return struct{}{}, errTeapot }, | |
74 | DecodeRequestFunc: func(*http.Request) (interface{}, error) { return struct{}{}, nil }, | |
75 | EncodeResponseFunc: func(http.ResponseWriter, interface{}) error { return nil }, | |
76 | ErrorEncoder: func(w http.ResponseWriter, err error) { w.WriteHeader(code(err)) }, | |
77 | Logger: log.NewNopLogger(), | |
78 | } | |
67 | handler := httptransport.NewServer( | |
68 | context.Background(), | |
69 | func(context.Context, interface{}) (interface{}, error) { return struct{}{}, errTeapot }, | |
70 | func(*http.Request) (interface{}, error) { return struct{}{}, nil }, | |
71 | func(http.ResponseWriter, interface{}) error { return nil }, | |
72 | httptransport.ServerErrorEncoder(func(w http.ResponseWriter, err error) { w.WriteHeader(code(err)) }), | |
73 | ) | |
79 | 74 | server := httptest.NewServer(handler) |
80 | 75 | defer server.Close() |
81 | 76 | resp, _ := http.Get(server.URL) |
101 | 96 | stepch = make(chan bool) |
102 | 97 | endpoint = func(context.Context, interface{}) (interface{}, error) { <-stepch; return struct{}{}, nil } |
103 | 98 | response = make(chan *http.Response) |
104 | handler = httptransport.Server{ | |
105 | Context: ctx, | |
106 | Endpoint: endpoint, | |
107 | DecodeRequestFunc: func(*http.Request) (interface{}, error) { return struct{}{}, nil }, | |
108 | EncodeResponseFunc: func(http.ResponseWriter, interface{}) error { return nil }, | |
109 | Before: []httptransport.RequestFunc{func(ctx context.Context, r *http.Request) context.Context { return ctx }}, | |
110 | After: []httptransport.ResponseFunc{func(ctx context.Context, w http.ResponseWriter) { return }}, | |
111 | Logger: log.NewNopLogger(), | |
112 | } | |
99 | handler = httptransport.NewServer( | |
100 | ctx, | |
101 | endpoint, | |
102 | func(*http.Request) (interface{}, error) { return struct{}{}, nil }, | |
103 | func(http.ResponseWriter, interface{}) error { return nil }, | |
104 | httptransport.ServerBefore(func(ctx context.Context, r *http.Request) context.Context { return ctx }), | |
105 | httptransport.ServerAfter(func(ctx context.Context, w http.ResponseWriter) { return }), | |
106 | ) | |
113 | 107 | ) |
114 | 108 | go func() { |
115 | 109 | server := httptest.NewServer(handler) |