Codebase list golang-github-go-kit-kit / bcbfb94
transport/http: {Encode,Decode}{Request,Response}Func Peter Bourgon 8 years ago
13 changed file(s) with 147 addition(s) and 113 deletion(s). Raw diff Collapse all Expand all
11
22 import (
33 "encoding/json"
4 "io"
54 "net/http"
65
76 "golang.org/x/net/context"
1211 )
1312
1413 func makeHTTPBinding(ctx context.Context, e endpoint.Endpoint, before []httptransport.RequestFunc, after []httptransport.ResponseFunc) http.Handler {
15 decode := func(r io.Reader) (interface{}, error) {
14 decode := func(r *http.Request) (interface{}, error) {
1615 var request reqrep.AddRequest
17 if err := json.NewDecoder(r).Decode(&request); err != nil {
16 if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
1817 return nil, err
1918 }
2019 return request, nil
2120 }
22 encode := func(w io.Writer, response interface{}) error {
21 encode := func(w http.ResponseWriter, response interface{}) error {
2322 return json.NewEncoder(w).Encode(response)
2423 }
2524 return httptransport.Server{
26 Context: ctx,
27 Endpoint: e,
28 DecodeFunc: decode,
29 EncodeFunc: encode,
30 Before: before,
31 After: append([]httptransport.ResponseFunc{httptransport.SetContentType("application/json; charset=utf-8")}, after...),
25 Context: ctx,
26 Endpoint: e,
27 DecodeRequestFunc: decode,
28 EncodeResponseFunc: encode,
29 Before: before,
30 After: append([]httptransport.ResponseFunc{httptransport.SetContentType("application/json; charset=utf-8")}, after...),
3231 }
3332 }
22 import (
33 "encoding/json"
44 "errors"
5 "io"
65 "log"
76 "net/http"
87 "strings"
3736 svc := stringService{}
3837
3938 uppercaseHandler := httptransport.Server{
40 Context: ctx,
41 Endpoint: makeUppercaseEndpoint(svc),
42 DecodeFunc: decodeUppercaseRequest,
43 EncodeFunc: encodeResponse,
39 Context: ctx,
40 Endpoint: makeUppercaseEndpoint(svc),
41 DecodeRequestFunc: decodeUppercaseRequest,
42 EncodeResponseFunc: encodeResponse,
4443 }
4544
4645 countHandler := httptransport.Server{
47 Context: ctx,
48 Endpoint: makeCountEndpoint(svc),
49 DecodeFunc: decodeCountRequest,
50 EncodeFunc: encodeResponse,
46 Context: ctx,
47 Endpoint: makeCountEndpoint(svc),
48 DecodeRequestFunc: decodeCountRequest,
49 EncodeResponseFunc: encodeResponse,
5150 }
5251
5352 http.Handle("/uppercase", uppercaseHandler)
7170 }
7271 }
7372
74 func decodeUppercaseRequest(r io.Reader) (interface{}, error) {
73 func decodeUppercaseRequest(r *http.Request) (interface{}, error) {
7574 var request uppercaseRequest
76 if err := json.NewDecoder(r).Decode(&request); err != nil {
75 if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
7776 return nil, err
7877 }
7978 return request, nil
8079 }
8180
82 func decodeCountRequest(r io.Reader) (interface{}, error) {
81 func decodeCountRequest(r *http.Request) (interface{}, error) {
8382 var request countRequest
84 if err := json.NewDecoder(r).Decode(&request); err != nil {
83 if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
8584 return nil, err
8685 }
8786 return request, nil
8887 }
8988
90 func encodeResponse(w io.Writer, response interface{}) error {
89 func encodeResponse(w http.ResponseWriter, response interface{}) error {
9190 return json.NewEncoder(w).Encode(response)
9291 }
9392
4343 svc = instrumentingMiddleware{requestCount, requestLatency, countResult, svc}
4444
4545 uppercaseHandler := httptransport.Server{
46 Context: ctx,
47 Endpoint: makeUppercaseEndpoint(svc),
48 DecodeFunc: decodeUppercaseRequest,
49 EncodeFunc: encodeResponse,
46 Context: ctx,
47 Endpoint: makeUppercaseEndpoint(svc),
48 DecodeRequestFunc: decodeUppercaseRequest,
49 EncodeResponseFunc: encodeResponse,
5050 }
5151
5252 countHandler := httptransport.Server{
53 Context: ctx,
54 Endpoint: makeCountEndpoint(svc),
55 DecodeFunc: decodeCountRequest,
56 EncodeFunc: encodeResponse,
53 Context: ctx,
54 Endpoint: makeCountEndpoint(svc),
55 DecodeRequestFunc: decodeCountRequest,
56 EncodeResponseFunc: encodeResponse,
5757 }
5858
5959 http.Handle("/uppercase", uppercaseHandler)
11
22 import (
33 "encoding/json"
4 "io"
4 "net/http"
55
66 "golang.org/x/net/context"
77
2424 }
2525 }
2626
27 func decodeUppercaseRequest(r io.Reader) (interface{}, error) {
27 func decodeUppercaseRequest(r *http.Request) (interface{}, error) {
2828 var request uppercaseRequest
29 if err := json.NewDecoder(r).Decode(&request); err != nil {
29 if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
3030 return nil, err
3131 }
3232 return request, nil
3333 }
3434
35 func decodeCountRequest(r io.Reader) (interface{}, error) {
35 func decodeCountRequest(r *http.Request) (interface{}, error) {
3636 var request countRequest
37 if err := json.NewDecoder(r).Decode(&request); err != nil {
37 if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
3838 return nil, err
3939 }
4040 return request, nil
4141 }
4242
43 func encodeResponse(w io.Writer, response interface{}) error {
43 func encodeResponse(w http.ResponseWriter, response interface{}) error {
4444 return json.NewEncoder(w).Encode(response)
4545 }
4646
5454 svc = instrumentingMiddleware(requestCount, requestLatency, countResult)(svc)
5555
5656 uppercaseHandler := httptransport.Server{
57 Context: ctx,
58 Endpoint: makeUppercaseEndpoint(svc),
59 DecodeFunc: decodeUppercaseRequest,
60 EncodeFunc: encode,
57 Context: ctx,
58 Endpoint: makeUppercaseEndpoint(svc),
59 DecodeRequestFunc: decodeUppercaseRequest,
60 EncodeResponseFunc: encodeResponse,
6161 }
6262 countHandler := httptransport.Server{
63 Context: ctx,
64 Endpoint: makeCountEndpoint(svc),
65 DecodeFunc: decodeCountRequest,
66 EncodeFunc: encode,
63 Context: ctx,
64 Endpoint: makeCountEndpoint(svc),
65 DecodeRequestFunc: decodeCountRequest,
66 EncodeResponseFunc: encodeResponse,
6767 }
6868
6969 http.Handle("/uppercase", uppercaseHandler)
8181 u.Path = "/uppercase"
8282 }
8383 return (httptransport.Client{
84 Client: http.DefaultClient,
85 Method: "GET",
86 URL: u,
87 Context: ctx,
88 EncodeFunc: encode,
89 DecodeFunc: decodeUppercaseResponse,
84 Client: http.DefaultClient,
85 Method: "GET",
86 URL: u,
87 Context: ctx,
88 DecodeResponseFunc: decodeUppercaseResponse,
89 EncodeRequestFunc: encodeRequest,
9090 }).Endpoint()
9191 }
9292
00 package main
11
22 import (
3 "bytes"
34 "encoding/json"
4 "io"
5 "io/ioutil"
6 "net/http"
57
68 "golang.org/x/net/context"
79
2426 }
2527 }
2628
27 func decodeUppercaseRequest(r io.Reader) (interface{}, error) {
29 func decodeUppercaseRequest(r *http.Request) (interface{}, error) {
2830 var request uppercaseRequest
29 if err := json.NewDecoder(r).Decode(&request); err != nil {
31 if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
3032 return nil, err
3133 }
3234 return request, nil
3335 }
3436
35 func decodeCountRequest(r io.Reader) (interface{}, error) {
37 func decodeCountRequest(r *http.Request) (interface{}, error) {
3638 var request countRequest
37 if err := json.NewDecoder(r).Decode(&request); err != nil {
39 if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
3840 return nil, err
3941 }
4042 return request, nil
4143 }
4244
43 func decodeUppercaseResponse(r io.Reader) (interface{}, error) {
45 func decodeUppercaseResponse(r *http.Response) (interface{}, error) {
4446 var response uppercaseResponse
45 if err := json.NewDecoder(r).Decode(&response); err != nil {
47 if err := json.NewDecoder(r.Body).Decode(&response); err != nil {
4648 return nil, err
4749 }
4850 return response, nil
4951 }
5052
51 func encode(w io.Writer, response interface{}) error {
53 func encodeResponse(w http.ResponseWriter, response interface{}) error {
5254 return json.NewEncoder(w).Encode(response)
55 }
56
57 func encodeRequest(r *http.Request, request interface{}) error {
58 var buf bytes.Buffer
59 if err := json.NewEncoder(&buf).Encode(request); err != nil {
60 return err
61 }
62 r.Body = ioutil.NopCloser(&buf)
63 return nil
5364 }
5465
5566 type uppercaseRequest struct {
00 package http
11
22 import (
3 "bytes"
43 "fmt"
54 "net/http"
65 "net/url"
2423 // A background context must be provided.
2524 context.Context
2625
27 // EncodeFunc, used to encode request types, must be provided.
28 EncodeFunc
26 // EncodeRequestFunc must be provided. The HTTP request passed to the
27 // EncodeRequestFunc will have a nil body.
28 EncodeRequestFunc
2929
30 // DecodeFunc, used to decode response types, must be provided.
31 DecodeFunc
30 // DecodeResponseFunc must be provided.
31 DecodeResponseFunc
3232
3333 // Before functions are executed on the outgoing request after it is
3434 // created, but before it's sent to the HTTP client. Clients have no After
4343 ctx, cancel := context.WithCancel(ctx)
4444 defer cancel()
4545
46 var buf bytes.Buffer
47 if err := c.EncodeFunc(&buf, request); err != nil {
48 return nil, fmt.Errorf("Encode: %v", err)
46 req, err := http.NewRequest(c.Method, c.URL.String(), nil)
47 if err != nil {
48 return nil, fmt.Errorf("NewRequest: %v", err)
4949 }
5050
51 req, err := http.NewRequest(c.Method, c.URL.String(), &buf)
52 if err != nil {
53 return nil, fmt.Errorf("NewRequest: %v", err)
51 if err = c.EncodeRequestFunc(req, request); err != nil {
52 return nil, fmt.Errorf("Encode: %v", err)
5453 }
5554
5655 for _, f := range c.Before {
6867 }
6968 defer func() { _ = resp.Body.Close() }()
7069
71 response, err := c.DecodeFunc(resp.Body)
70 response, err := c.DecodeResponseFunc(resp)
7271 if err != nil {
7372 return nil, fmt.Errorf("Decode: %v", err)
7473 }
00 package http_test
11
22 import (
3 "io"
43 "net/http"
54 "net/http/httptest"
65 "net/url"
1413
1514 func TestHTTPClient(t *testing.T) {
1615 var (
17 decode = func(r io.Reader) (interface{}, error) { return struct{}{}, nil }
18 encode = func(w io.Writer, response interface{}) error { return nil }
16 encode = func(*http.Request, interface{}) error { return nil }
17 decode = func(*http.Response) (interface{}, error) { return struct{}{}, nil }
1918 headers = make(chan string, 1)
2019 headerKey = "X-Foo"
2120 headerVal = "abcde"
2726 }))
2827
2928 client := httptransport.Client{
30 Method: "GET",
31 URL: mustParse(server.URL),
32 Context: context.Background(),
33 DecodeFunc: decode,
34 EncodeFunc: encode,
35 Before: []httptransport.RequestFunc{httptransport.SetRequestHeader(headerKey, headerVal)},
29 Method: "GET",
30 URL: mustParse(server.URL),
31 Context: context.Background(),
32 EncodeRequestFunc: encode,
33 DecodeResponseFunc: decode,
34 Before: []httptransport.RequestFunc{httptransport.SetRequestHeader(headerKey, headerVal)},
3635 }
3736
3837 _, err := client.Endpoint()(context.Background(), struct{}{})
00 package http
11
2 import "io"
2 import "net/http"
33
4 // DecodeFunc converts a serialized request (server) or response (client) to a
5 // user version of the same. One straightforward DecodeFunc could be something
6 // that JSON-decodes the reader to a concrete type.
7 type DecodeFunc func(io.Reader) (interface{}, error)
4 // DecodeRequestFunc extracts a user-domain request object from an HTTP
5 // request object. It's designed to be used in HTTP servers, for server-side
6 // endpoints. One straightforward DecodeRequestFunc could be something that
7 // JSON decodes from the request body to the concrete response type.
8 type DecodeRequestFunc func(*http.Request) (request interface{}, err error)
89
9 // EncodeFunc converts a user response (server) or request (client) to a
10 // serialized version of the same, by encoding the interface to the writer.
11 type EncodeFunc func(io.Writer, interface{}) error
10 // EncodeRequestFunc encodes the passed request object into the HTTP request
11 // object. It's designed to be used in HTTP clients, for client-side
12 // endpoints. One straightforward EncodeRequestFunc could something that JSON
13 // encodes the object directly to the request body.
14 type EncodeRequestFunc func(*http.Request, interface{}) error
15
16 // EncodeResponseFunc encodes the passed response object to the HTTP response
17 // writer. It's designed to be used in HTTP servers, for server-side
18 // endpoints. One straightforward EncodeResponseFunc could be something that
19 // JSON encodes the object directly to the response body.
20 type EncodeResponseFunc func(http.ResponseWriter, interface{}) error
21
22 // DecodeResponseFunc extracts a user-domain response object from an HTTP
23 // response object. It's designed to be used in HTTP clients, for client-side
24 // endpoints. One straightforward DecodeResponseFunc could be something that
25 // JSON decodes from the response body to the concrete response type.
26 type DecodeResponseFunc func(*http.Response) (response interface{}, err error)
99
1010 // Server wraps an endpoint and implements http.Handler.
1111 type Server struct {
12 // A background context must be provided.
1213 context.Context
14
15 // The endpoint that will be invoked.
1316 endpoint.Endpoint
14 DecodeFunc
15 EncodeFunc
17
18 // DecodeRequestFunc must be provided.
19 DecodeRequestFunc
20
21 // EncodeResponseFunc must be provided.
22 EncodeResponseFunc
23
24 // Before functions are executed on the HTTP request object before the
25 // request is decoded.
1626 Before []RequestFunc
17 After []ResponseFunc
27
28 // After functions are executed on the HTTP response writer after the
29 // endpoint is invoked, but before anything is written to the client.
30 After []ResponseFunc
1831 }
1932
2033 // ServeHTTP implements http.Handler.
2639 ctx = f(ctx, r)
2740 }
2841
29 request, err := b.DecodeFunc(r.Body)
42 request, err := b.DecodeRequestFunc(r)
3043 if err != nil {
3144 http.Error(w, err.Error(), http.StatusBadRequest)
3245 return
4659 f(ctx, w)
4760 }
4861
49 if err := b.EncodeFunc(w, response); err != nil {
62 if err := b.EncodeResponseFunc(w, response); err != nil {
5063 http.Error(w, err.Error(), http.StatusInternalServerError)
5164 return
5265 }
11
22 import (
33 "errors"
4 "io"
54 "io/ioutil"
65 "net/http"
76 "net/http/httptest"
1413
1514 func TestServerBadDecode(t *testing.T) {
1615 handler := httptransport.Server{
17 Context: context.Background(),
18 Endpoint: func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil },
19 DecodeFunc: func(io.Reader) (interface{}, error) { return struct{}{}, errors.New("dang") },
20 EncodeFunc: func(io.Writer, interface{}) error { return nil },
16 Context: context.Background(),
17 Endpoint: func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil },
18 DecodeRequestFunc: func(*http.Request) (interface{}, error) { return struct{}{}, errors.New("dang") },
19 EncodeResponseFunc: func(http.ResponseWriter, interface{}) error { return nil },
2120 }
2221 server := httptest.NewServer(handler)
2322 defer server.Close()
2928
3029 func TestServerBadEndpoint(t *testing.T) {
3130 handler := httptransport.Server{
32 Context: context.Background(),
33 Endpoint: func(context.Context, interface{}) (interface{}, error) { return struct{}{}, errors.New("dang") },
34 DecodeFunc: func(io.Reader) (interface{}, error) { return struct{}{}, nil },
35 EncodeFunc: func(io.Writer, interface{}) error { return nil },
31 Context: context.Background(),
32 Endpoint: func(context.Context, interface{}) (interface{}, error) { return struct{}{}, errors.New("dang") },
33 DecodeRequestFunc: func(*http.Request) (interface{}, error) { return struct{}{}, nil },
34 EncodeResponseFunc: func(http.ResponseWriter, interface{}) error { return nil },
3635 }
3736 server := httptest.NewServer(handler)
3837 defer server.Close()
4443
4544 func TestServerBadEncode(t *testing.T) {
4645 handler := httptransport.Server{
47 Context: context.Background(),
48 Endpoint: func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil },
49 DecodeFunc: func(io.Reader) (interface{}, error) { return struct{}{}, nil },
50 EncodeFunc: func(io.Writer, interface{}) error { return errors.New("dang") },
46 Context: context.Background(),
47 Endpoint: func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil },
48 DecodeRequestFunc: func(*http.Request) (interface{}, error) { return struct{}{}, nil },
49 EncodeResponseFunc: func(http.ResponseWriter, interface{}) error { return errors.New("dang") },
5150 }
5251 server := httptest.NewServer(handler)
5352 defer server.Close()
7574 endpoint = func(context.Context, interface{}) (interface{}, error) { <-stepch; return struct{}{}, nil }
7675 response = make(chan *http.Response)
7776 handler = httptransport.Server{
78 Context: ctx,
79 Endpoint: endpoint,
80 DecodeFunc: func(io.Reader) (interface{}, error) { return struct{}{}, nil },
81 EncodeFunc: func(io.Writer, interface{}) error { return nil },
82 Before: []httptransport.RequestFunc{func(ctx context.Context, r *http.Request) context.Context { return ctx }},
83 After: []httptransport.ResponseFunc{func(ctx context.Context, w http.ResponseWriter) { return }},
77 Context: ctx,
78 Endpoint: endpoint,
79 DecodeRequestFunc: func(*http.Request) (interface{}, error) { return struct{}{}, nil },
80 EncodeResponseFunc: func(http.ResponseWriter, interface{}) error { return nil },
81 Before: []httptransport.RequestFunc{func(ctx context.Context, r *http.Request) context.Context { return ctx }},
82 After: []httptransport.ResponseFunc{func(ctx context.Context, w http.ResponseWriter) { return }},
8483 }
8584 )
8685 go func() {