Codebase list golang-github-go-kit-kit / d61f875 transport / http / client.go
d61f875

Tree @d61f875 (Download .tar.gz)

client.go @d61f875raw · history · blame

package http

import (
	"bytes"
	"net/http"
	"net/url"

	"golang.org/x/net/context"

	"github.com/go-kit/kit/endpoint"
	"github.com/go-kit/kit/transport/codec"
)

type httpClient struct {
	*url.URL
	codec.Codec
	method string
	*http.Client
	before       []BeforeFunc
	makeResponse func() interface{}
}

// NewClient returns a client endpoint for a remote service. addr must be a
// valid, parseable URL, including the scheme and path.
func NewClient(addr string, cdc codec.Codec, makeResponse func() interface{}, options ...ClientOption) endpoint.Endpoint {
	u, err := url.Parse(addr)
	if err != nil {
		panic(err)
	}
	c := httpClient{
		URL:          u,
		Codec:        cdc,
		method:       "GET",
		Client:       http.DefaultClient,
		makeResponse: makeResponse,
	}
	for _, option := range options {
		option(&c)
	}
	return c.endpoint
}

func (c httpClient) endpoint(ctx context.Context, request interface{}) (interface{}, error) {
	var buf bytes.Buffer
	if err := c.Codec.Encode(&buf, request); err != nil {
		return nil, err
	}

	req, err := http.NewRequest(c.method, c.URL.String(), &buf)
	if err != nil {
		return nil, err
	}

	for _, f := range c.before {
		f(ctx, req)
	}

	resp, err := c.Client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	response := c.makeResponse()
	ctx, err = c.Codec.Decode(ctx, resp.Body, response)
	if err != nil {
		return nil, err
	}

	return response, nil
}

// ClientOption sets a parameter for the HTTP client.
type ClientOption func(*httpClient)

// ClientBefore adds pre-invocation BeforeFuncs to the HTTP client.
func ClientBefore(funcs ...BeforeFunc) ClientOption {
	return func(c *httpClient) { c.before = append(c.before, funcs...) }
}

// ClientMethod sets the method used to invoke the RPC. By default, it's GET.
func ClientMethod(method string) ClientOption {
	return func(c *httpClient) { c.method = method }
}

// SetClient sets the HTTP client struct used to invoke the RPC. By default,
// it's http.DefaultClient.
func SetClient(client *http.Client) ClientOption {
	return func(c *httpClient) { c.Client = client }
}