func DefaultErrorParser(resp *http.Response) error {
	resBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	rerr := new(Error)
	err = json.Unmarshal(resBody, rerr)
	if err != nil {
		return fmt.Errorf("invalid response body: %s", string(resBody))
	}
	if rerr.Title == "" {
		return fmt.Errorf("invalid response body: %s", string(resBody))
	} else {
		rerr.Status = resp.StatusCode
		return rerr
	}
}
DefaultErrorParser attempts to parse the response body as a rest.Error. If
it cannot do so, return an error containing the entire response body.
package rest
import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"runtime"
	"strings"
	"time"
)
type UploadType string
var JSON UploadType = "application/json"
var FormURLEncoded UploadType = "application/x-www-form-urlencoded"
const Version = "2.1"
var ua string
func init() {
	gv := strings.Replace(runtime.Version(), "go", "", 1)
	ua = fmt.Sprintf("rest-client/%s (https://github.com/kevinburke/rest) go/%s (%s/%s)",
		Version, gv, runtime.GOOS, runtime.GOARCH)
}
type Client struct {
	ID string
	Token string
	Client *http.Client
	Base string
	UploadType UploadType
	ErrorParser func(*http.Response) error
}
func NewClient(user, pass, base string) *Client {
	return &Client{
		ID:          user,
		Token:       pass,
		Client:      defaultHttpClient,
		Base:        base,
		UploadType:  JSON,
		ErrorParser: DefaultErrorParser,
	}
}
var defaultDialer = &net.Dialer{
	Timeout:   30 * time.Second,
	KeepAlive: 30 * time.Second,
	DualStack: true,
}
func (c *Client) DialSocket(socket string, transport *http.Transport) {
	dialSock := func(ctx context.Context, proto, addr string) (conn net.Conn, err error) {
		return defaultDialer.DialContext(ctx, "unix", socket)
	}
	if transport == nil {
		ht := http.DefaultTransport.(*http.Transport)
		transport = &http.Transport{
			Proxy:                 ht.Proxy,
			MaxIdleConns:          ht.MaxIdleConns,
			IdleConnTimeout:       ht.IdleConnTimeout,
			TLSHandshakeTimeout:   ht.TLSHandshakeTimeout,
			ExpectContinueTimeout: ht.ExpectContinueTimeout,
			DialContext:           dialSock,
		}
	}
	if c.Client == nil {
		c.Client = &http.Client{
			Timeout: defaultHttpClient.Timeout,
		}
	}
	switch tp := c.Client.Transport.(type) {
	case nil, *Transport:
		c.Client.Transport = &Transport{
			RoundTripper: transport,
			Debug:        DefaultTransport.Debug,
			Output:       DefaultTransport.Output,
		}
	case *http.Transport:
		tp = transport
	default:
		panic(fmt.Sprintf("could not set DialSocket on unknown transport: %#v", tp))
	}
}
func (c *Client) NewRequest(method, path string, body io.Reader) (*http.Request, error) {
	req, err := http.NewRequest(method, c.Base+path, body)
	if err != nil {
		return nil, err
	}
	if c.ID != "" || c.Token != "" {
		req.SetBasicAuth(c.ID, c.Token)
	}
	req.Header.Add("User-Agent", ua)
	req.Header.Add("Accept", "application/json")
	req.Header.Add("Accept-Charset", "utf-8")
	if method == "POST" || method == "PUT" {
		uploadType := c.UploadType
		if uploadType == "" {
			uploadType = JSON
		}
		req.Header.Add("Content-Type", fmt.Sprintf("%s; charset=utf-8", uploadType))
	}
	return req, nil
}
func (c *Client) Do(r *http.Request, v interface{}) error {
	var res *http.Response
	var err error
	if c.Client == nil {
		res, err = defaultHttpClient.Do(r)
	} else {
		res, err = c.Client.Do(r)
	}
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if res.StatusCode >= 400 {
		if c.ErrorParser != nil {
			return c.ErrorParser(res)
		}
		return DefaultErrorParser(res)
	}
	resBody, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return err
	}
	if v == nil || res.StatusCode == http.StatusNoContent {
		return nil
	} else {
		return json.Unmarshal(resBody, v)
	}
}