@@ -21,9 +21,7 @@ type HTTPClient interface {
2121// Client wraps a URL and provides a method that implements endpoint.Endpoint.
2222type Client struct {
2323 client HTTPClient
24- method string
25- tgt * url.URL
26- enc EncodeRequestFunc
24+ req CreateRequestFunc
2725 dec DecodeResponseFunc
2826 before []RequestFunc
2927 after []ClientResponseFunc
@@ -32,22 +30,18 @@ type Client struct {
3230}
3331
3432// NewClient constructs a usable Client for a single remote method.
35- func NewClient (
36- method string ,
37- tgt * url.URL ,
38- enc EncodeRequestFunc ,
39- dec DecodeResponseFunc ,
40- options ... ClientOption ,
41- ) * Client {
33+ func NewClient (method string , tgt * url.URL , enc EncodeRequestFunc , dec DecodeResponseFunc , options ... ClientOption ) * Client {
34+ return NewExplicitClient (makeCreateRequestFunc (method , tgt , enc ), dec , options ... )
35+ }
36+
37+ // NewExplicitClient is like NewClient but uses a CreateRequestFunc instead of a
38+ // method, target URL, and EncodeRequestFunc, which allows for more control over
39+ // the outgoing HTTP request.
40+ func NewExplicitClient (req CreateRequestFunc , dec DecodeResponseFunc , options ... ClientOption ) * Client {
4241 c := & Client {
43- client : http .DefaultClient ,
44- method : method ,
45- tgt : tgt ,
46- enc : enc ,
47- dec : dec ,
48- before : []RequestFunc {},
49- after : []ClientResponseFunc {},
50- bufferedStream : false ,
42+ client : http .DefaultClient ,
43+ req : req ,
44+ dec : dec ,
5145 }
5246 for _ , option := range options {
5347 option (c )
@@ -64,33 +58,35 @@ func SetClient(client HTTPClient) ClientOption {
6458 return func (c * Client ) { c .client = client }
6559}
6660
67- // ClientBefore sets the RequestFuncs that are applied to the outgoing HTTP
61+ // ClientBefore adds one or more RequestFuncs to be applied to the outgoing HTTP
6862// request before it's invoked.
6963func ClientBefore (before ... RequestFunc ) ClientOption {
7064 return func (c * Client ) { c .before = append (c .before , before ... ) }
7165}
7266
73- // ClientAfter sets the ClientResponseFuncs applied to the incoming HTTP
74- // request prior to it being decoded. This is useful for obtaining anything off
75- // of the response and adding onto the context prior to decoding.
67+ // ClientAfter adds one or more ClientResponseFuncs, which are applied to the
68+ // incoming HTTP response prior to it being decoded. This is useful for
69+ // obtaining anything off of the response and adding it into the context prior
70+ // to decoding.
7671func ClientAfter (after ... ClientResponseFunc ) ClientOption {
7772 return func (c * Client ) { c .after = append (c .after , after ... ) }
7873}
7974
80- // ClientFinalizer is executed at the end of every HTTP request.
81- // By default, no finalizer is registered.
75+ // ClientFinalizer adds one or more ClientFinalizerFuncs to be executed at the
76+ // end of every HTTP request. Finalizers are executed in the order in which they
77+ // were added. By default, no finalizer is registered.
8278func ClientFinalizer (f ... ClientFinalizerFunc ) ClientOption {
8379 return func (s * Client ) { s .finalizer = append (s .finalizer , f ... ) }
8480}
8581
86- // BufferedStream sets whether the Response.Body is left open, allowing it
82+ // BufferedStream sets whether the HTTP response body is left open, allowing it
8783// to be read from later. Useful for transporting a file as a buffered stream.
88- // That body has to be Closed to propery end the request.
84+ // That body has to be drained and closed to properly end the request.
8985func BufferedStream (buffered bool ) ClientOption {
9086 return func (c * Client ) { c .bufferedStream = buffered }
9187}
9288
93- // Endpoint returns a usable endpoint that invokes the remote endpoint.
89+ // Endpoint returns a usable Go kit endpoint that calls the remote HTTP endpoint.
9490func (c Client ) Endpoint () endpoint.Endpoint {
9591 return func (ctx context.Context , request interface {}) (interface {}, error ) {
9692 ctx , cancel := context .WithCancel (ctx )
@@ -111,30 +107,25 @@ func (c Client) Endpoint() endpoint.Endpoint {
111107 }()
112108 }
113109
114- req , err := http . NewRequest ( c . method , c . tgt . String (), nil )
110+ req , err := c . req ( ctx , request )
115111 if err != nil {
116112 cancel ()
117113 return nil , err
118114 }
119115
120- if err = c .enc (ctx , req , request ); err != nil {
121- cancel ()
122- return nil , err
123- }
124-
125116 for _ , f := range c .before {
126117 ctx = f (ctx , req )
127118 }
128119
129120 resp , err = c .client .Do (req .WithContext (ctx ))
130-
131121 if err != nil {
132122 cancel ()
133123 return nil , err
134124 }
135125
136- // If we expect a buffered stream, we don't cancel the context when the endpoint returns.
137- // Instead, we should call the cancel func when closing the response body.
126+ // If the caller asked for a buffered stream, we don't cancel the
127+ // context when the endpoint returns. Instead, we should call the
128+ // cancel func when closing the response body.
138129 if c .bufferedStream {
139130 resp .Body = bodyWithCancel {ReadCloser : resp .Body , cancel : cancel }
140131 } else {
@@ -207,3 +198,22 @@ func EncodeXMLRequest(c context.Context, r *http.Request, request interface{}) e
207198 r .Body = ioutil .NopCloser (& b )
208199 return xml .NewEncoder (& b ).Encode (request )
209200}
201+
202+ //
203+ //
204+ //
205+
206+ func makeCreateRequestFunc (method string , target * url.URL , enc EncodeRequestFunc ) CreateRequestFunc {
207+ return func (ctx context.Context , request interface {}) (* http.Request , error ) {
208+ req , err := http .NewRequest (method , target .String (), nil )
209+ if err != nil {
210+ return nil , err
211+ }
212+
213+ if err = enc (ctx , req , request ); err != nil {
214+ return nil , err
215+ }
216+
217+ return req , nil
218+ }
219+ }
0 commit comments