Codebase list golang-github-go-kit-kit / 20dc1a1
Move HTTP client to transport/http Peter Bourgon 8 years ago
7 changed file(s) with 167 addition(s) and 94 deletion(s). Raw diff Collapse all Expand all
00 package main
11
22 import (
3 "bytes"
4 "net/http"
5 "net/url"
6 "strings"
7
8 "github.com/go-kit/kit/log"
9
103 "golang.org/x/net/context"
114
125 "github.com/go-kit/kit/client"
13 "github.com/go-kit/kit/transport/codec"
14 httptransport "github.com/go-kit/kit/transport/http"
6 "github.com/go-kit/kit/log"
157 )
168
179 // Add is the abstract definition of what this service does. It could easily
1911 // be an endpoint.
2012 type Add func(context.Context, int64, int64) int64
2113
14 // pureAdd implements Add with no dependencies.
2215 func pureAdd(_ context.Context, a, b int64) int64 { return a + b }
2316
17 // proxyAdd implements Add by invoking a remote Add service.
2418 func proxyAdd(e client.Endpoint) Add {
2519 return func(ctx context.Context, a, b int64) int64 {
2620 resp, err := e(ctx, &addRequest{a, b})
3630 return addResp.V
3731 }
3832 }
39
40 type httpClient struct {
41 *url.URL
42 codec.Codec
43 method string
44 *http.Client
45 before []httptransport.BeforeFunc
46 makeResponse func() interface{}
47 }
48
49 // TODO this needs to go to package client
50 func newHTTPClient(addr string, cdc codec.Codec, makeResponse func() interface{}, options ...httpClientOption) client.Endpoint {
51 if !strings.HasPrefix(addr, "http") {
52 addr = "http://" + addr
53 }
54 u, err := url.Parse(addr)
55 if err != nil {
56 panic(err)
57 }
58
59 c := httpClient{
60 URL: u,
61 Codec: cdc,
62 method: "GET",
63 Client: http.DefaultClient,
64 makeResponse: makeResponse,
65 }
66 for _, option := range options {
67 option(&c)
68 }
69 return c.endpoint
70 }
71
72 func (c httpClient) endpoint(ctx context.Context, request interface{}) (interface{}, error) {
73 var buf bytes.Buffer
74 if err := c.Codec.Encode(&buf, request); err != nil {
75 return nil, err
76 }
77
78 req, err := http.NewRequest(c.method, c.URL.String(), &buf)
79 if err != nil {
80 return nil, err
81 }
82
83 for _, f := range c.before {
84 f(ctx, req)
85 }
86
87 resp, err := c.Client.Do(req)
88 if err != nil {
89 return nil, err
90 }
91 defer resp.Body.Close()
92
93 response := c.makeResponse()
94 ctx, err = c.Codec.Decode(ctx, resp.Body, response)
95 if err != nil {
96 return nil, err
97 }
98
99 return response, nil
100 }
101
102 type httpClientOption func(*httpClient)
103
104 func before(funcs ...httptransport.BeforeFunc) httpClientOption {
105 return func(c *httpClient) { c.before = append(c.before, funcs...) }
106 }
9797 makeResponse := func() interface{} { return &addResponse{} }
9898
9999 var e client.Endpoint
100 e = newHTTPClient(*proxyHTTPAddr, codec, makeResponse, before(zipkin.ToRequest(zipkinSpanFunc)))
100 e = httptransport.NewClient(*proxyHTTPAddr, codec, makeResponse, httptransport.ClientBefore(zipkin.ToRequest(zipkinSpanFunc)))
101101 e = zipkin.AnnotateClient(zipkinSpanFunc, zipkinCollector)(e)
102102
103103 a = proxyAdd(e)
130130 defer cancel()
131131
132132 field := metrics.Field{Key: "transport", Value: "http"}
133 before := httptransport.Before(zipkin.ToContext(zipkinSpanFunc))
134 after := httptransport.After(httptransport.SetContentType("application/json"))
133 before := httptransport.BindingBefore(zipkin.ToContext(zipkinSpanFunc))
134 after := httptransport.BindingAfter(httptransport.SetContentType("application/json"))
135135 makeRequest := func() interface{} { return &addRequest{} }
136136
137137 var handler http.Handler
0 package http_test
1
2 import (
3 "net/http/httptest"
4 "testing"
5
6 "golang.org/x/net/context"
7
8 httptransport "github.com/go-kit/kit/transport/http"
9 )
10
11 func TestSetContentType(t *testing.T) {
12 contentType := "application/whatever"
13 rec := httptest.NewRecorder()
14 httptransport.SetContentType(contentType)(context.Background(), rec)
15 if want, have := contentType, rec.Header().Get("Content-Type"); want != have {
16 t.Errorf("want %q, have %q", want, have)
17 }
18 }
77 "github.com/go-kit/kit/server"
88 "github.com/go-kit/kit/transport/codec"
99 )
10
11 // BindingOption sets a parameter for the binding.
12 type BindingOption func(*binding)
13
14 // Before adds pre-RPC BeforeFuncs to the binding.
15 func Before(funcs ...BeforeFunc) BindingOption {
16 return func(b *binding) { b.before = append(b.before, funcs...) }
17 }
18
19 // After adds post-RPC AfterFuncs to the binding.
20 func After(funcs ...AfterFunc) BindingOption {
21 return func(b *binding) { b.after = append(b.after, funcs...) }
22 }
2310
2411 type binding struct {
2512 context.Context
8067 return
8168 }
8269 }
70
71 // BindingOption sets a parameter for the HTTP binding.
72 type BindingOption func(*binding)
73
74 // BindingBefore adds pre-RPC BeforeFuncs to the HTTP binding.
75 func BindingBefore(funcs ...BeforeFunc) BindingOption {
76 return func(b *binding) { b.before = append(b.before, funcs...) }
77 }
78
79 // BindingAfter adds post-RPC AfterFuncs to the HTTP binding.
80 func BindingAfter(funcs ...AfterFunc) BindingOption {
81 return func(b *binding) { b.after = append(b.after, funcs...) }
82 }
5555 defer resp.Body.Close()
5656
5757 var r myResponse
58 if err := json.NewDecoder(resp.Body).Decode(&r); err != nil {
58 if _, err := codec.Decode(ctx, resp.Body, &r); err != nil {
5959 t.Fatal(err)
6060 }
6161
0 package http
1
2 import (
3 "bytes"
4 "net/http"
5 "net/url"
6
7 "golang.org/x/net/context"
8
9 "github.com/go-kit/kit/client"
10 "github.com/go-kit/kit/transport/codec"
11 )
12
13 type httpClient struct {
14 *url.URL
15 codec.Codec
16 method string
17 *http.Client
18 before []BeforeFunc
19 makeResponse func() interface{}
20 }
21
22 // NewClient returns a client endpoint for a remote service. addr must be a
23 // valid, parseable URL, including the scheme and path.
24 func NewClient(addr string, cdc codec.Codec, makeResponse func() interface{}, options ...ClientOption) client.Endpoint {
25 u, err := url.Parse(addr)
26 if err != nil {
27 panic(err)
28 }
29 c := httpClient{
30 URL: u,
31 Codec: cdc,
32 method: "GET",
33 Client: http.DefaultClient,
34 makeResponse: makeResponse,
35 }
36 for _, option := range options {
37 option(&c)
38 }
39 return c.endpoint
40 }
41
42 func (c httpClient) endpoint(ctx context.Context, request interface{}) (interface{}, error) {
43 var buf bytes.Buffer
44 if err := c.Codec.Encode(&buf, request); err != nil {
45 return nil, err
46 }
47
48 req, err := http.NewRequest(c.method, c.URL.String(), &buf)
49 if err != nil {
50 return nil, err
51 }
52
53 for _, f := range c.before {
54 f(ctx, req)
55 }
56
57 resp, err := c.Client.Do(req)
58 if err != nil {
59 return nil, err
60 }
61 defer resp.Body.Close()
62
63 response := c.makeResponse()
64 ctx, err = c.Codec.Decode(ctx, resp.Body, response)
65 if err != nil {
66 return nil, err
67 }
68
69 return response, nil
70 }
71
72 // ClientOption sets a parameter for the HTTP client.
73 type ClientOption func(*httpClient)
74
75 // ClientBefore adds pre-invocation BeforeFuncs to the HTTP client.
76 func ClientBefore(funcs ...BeforeFunc) ClientOption {
77 return func(c *httpClient) { c.before = append(c.before, funcs...) }
78 }
79
80 // ClientMethod sets the method used to invoke the RPC. By default, it's GET.
81 func ClientMethod(method string) ClientOption {
82 return func(c *httpClient) { c.method = method }
83 }
84
85 // SetClient sets the HTTP client struct used to invoke the RPC. By default,
86 // it's http.DefaultClient.
87 func SetClient(client *http.Client) ClientOption {
88 return func(c *httpClient) { c.Client = client }
89 }
0 package http_test
1
2 import (
3 "net/http"
4 "net/http/httptest"
5 "reflect"
6 "testing"
7
8 "golang.org/x/net/context"
9
10 jsoncodec "github.com/go-kit/kit/transport/codec/json"
11 httptransport "github.com/go-kit/kit/transport/http"
12 )
13
14 func TestClient(t *testing.T) {
15 type myResponse struct {
16 V int `json:"v"`
17 }
18 const v = 123
19 codec := jsoncodec.New()
20 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
21 codec.Encode(w, myResponse{v})
22 }))
23 defer server.Close()
24 makeResponse := func() interface{} { return &myResponse{} }
25 client := httptransport.NewClient(server.URL, codec, makeResponse)
26 resp, err := client(context.Background(), struct{}{})
27 if err != nil {
28 t.Fatal(err)
29 }
30 response, ok := resp.(*myResponse)
31 if !ok {
32 t.Fatalf("not myResponse (%s)", reflect.TypeOf(response))
33 }
34 if want, have := v, response.V; want != have {
35 t.Errorf("want %d, have %d", want, have)
36 }
37 }