func (c *Client) Get(ctx context.Context, endpoint string, params url.Values) (*Response, error) {
	if c.sanitizerEnabled {
		err := isPathSafe(endpoint)
		if err != nil {
			return nil, err
		}
	}
	baseUrl, err := url.Parse(endpoint)
	if err != nil {
		return nil, err
	}
	baseUrl.RawQuery = params.Encode()
	tracer := c.newTracer()
	return tracer.Done(c.RoundTrip(func() (*http.Response, error) {
		req, err := http.NewRequest(http.MethodGet, baseUrl.String(), nil)
		if err != nil {
			return nil, err
		}
		req = req.WithContext(ctx)
		c.addAuth(req)
		tracer.Start(req)
		return c.client.Do(req)
	}))
}
Get executes GET request to the server endpoint with optional query arguments passed in params

re, err := c.Get(c.Endpoint("users"), url.Values{"name": []string{"John"}})
package roundtrip
import (
	"bytes"
	"context"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"mime"
	"mime/multipart"
	"net/http"
	"net/url"
	"strings"
)
type ClientParam func(c *Client) error
func Tracer(newTracer NewTracer) ClientParam {
	return func(c *Client) error {
		c.newTracer = newTracer
		return nil
	}
}
func HTTPClient(h *http.Client) ClientParam {
	return func(c *Client) error {
		c.client = h
		return nil
	}
}
func BasicAuth(username, password string) ClientParam {
	return func(c *Client) error {
		c.auth = &basicAuth{username: username, password: password}
		return nil
	}
}
func BearerAuth(token string) ClientParam {
	return func(c *Client) error {
		c.auth = &bearerAuth{token: token}
		return nil
	}
}
func CookieJar(jar http.CookieJar) ClientParam {
	return func(c *Client) error {
		c.jar = jar
		return nil
	}
}
func SanitizerEnabled(sanitizerEnabled bool) ClientParam {
	return func(c *Client) error {
		c.sanitizerEnabled = sanitizerEnabled
		return nil
	}
}
type Client struct {
	addr string
	v string
	client *http.Client
	auth fmt.Stringer
	jar http.CookieJar
	newTracer NewTracer
	sanitizerEnabled bool
}
func NewClient(addr, v string, params ...ClientParam) (*Client, error) {
	c := &Client{
		addr:   addr,
		v:      v,
		client: &http.Client{},
	}
	for _, p := range params {
		if err := p(c); err != nil {
			return nil, err
		}
	}
	if c.jar != nil {
		c.client.Jar = c.jar
	}
	if c.newTracer == nil {
		c.newTracer = NewNopTracer
	}
	return c, nil
}
func (c *Client) HTTPClient() *http.Client {
	return c.client
}
func (c *Client) Endpoint(params ...string) string {
	if c.v != "" {
		return fmt.Sprintf("%s/%s/%s", c.addr, c.v, strings.Join(params, "/"))
	}
	return fmt.Sprintf("%s/%s", c.addr, strings.Join(params, "/"))
}
func (c *Client) PostForm(ctx context.Context, endpoint string, vals url.Values, files ...File) (*Response, error) {
	if c.sanitizerEnabled {
		err := isPathSafe(endpoint)
		if err != nil {
			return nil, err
		}
	}
	return c.RoundTrip(func() (*http.Response, error) {
		if len(files) == 0 {
			req, err := http.NewRequest(http.MethodPost, endpoint, strings.NewReader(vals.Encode()))
			if err != nil {
				return nil, err
			}
			req = req.WithContext(ctx)
			req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
			c.addAuth(req)
			return c.client.Do(req)
		}
		var buf bytes.Buffer
		buf.Grow(bufferSize)
		buffers := newBuffersFromFiles(files)
		writer := multipart.NewWriter(&limitWriter{&buf, bufferSize})
		err := writeForm(writer, vals, buffers...)
		writer.Close()
		if err != nil && err != errShortWrite {
			return nil, err
		}
		if err == errShortWrite {
			for i := range buffers {
				buffers[i].rewind()
			}
			return c.writeWithPipe(endpoint, vals, buffers...)
		}
		req, err := http.NewRequest(http.MethodPost, endpoint, &buf)
		if err != nil {
			return nil, err
		}
		req = req.WithContext(ctx)
		req.Header.Set("Content-Type",
			fmt.Sprintf(`multipart/form-data;boundary="%v"`, writer.Boundary()))
		c.addAuth(req)
		return c.client.Do(req)
	})
}
func (c *Client) PostJSON(ctx context.Context, endpoint string, data interface{}) (*Response, error) {
	if c.sanitizerEnabled {
		err := isPathSafe(endpoint)
		if err != nil {
			return nil, err
		}
	}
	tracer := c.newTracer()
	return tracer.Done(c.RoundTrip(func() (*http.Response, error) {
		data, err := json.Marshal(data)
		req, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewBuffer(data))
		if err != nil {
			return nil, err
		}
		req = req.WithContext(ctx)
		req.Header.Set("Content-Type", "application/json")
		c.addAuth(req)
		tracer.Start(req)
		return c.client.Do(req)
	}))
}
func (c *Client) PutJSON(ctx context.Context, endpoint string, data interface{}) (*Response, error) {
	if c.sanitizerEnabled {
		err := isPathSafe(endpoint)
		if err != nil {
			return nil, err
		}
	}
	tracer := c.newTracer()
	return tracer.Done(c.RoundTrip(func() (*http.Response, error) {
		data, err := json.Marshal(data)
		req, err := http.NewRequest(http.MethodPut, endpoint, bytes.NewBuffer(data))
		if err != nil {
			return nil, err
		}
		req = req.WithContext(ctx)
		req.Header.Set("Content-Type", "application/json")
		c.addAuth(req)
		tracer.Start(req)
		return c.client.Do(req)
	}))
}
func (c *Client) PatchJSON(ctx context.Context, endpoint string, data interface{}) (*Response, error) {
	if c.sanitizerEnabled {
		err := isPathSafe(endpoint)
		if err != nil {
			return nil, err
		}
	}
	tracer := c.newTracer()
	return tracer.Done(c.RoundTrip(func() (*http.Response, error) {
		data, err := json.Marshal(data)
		req, err := http.NewRequest(http.MethodPatch, endpoint, bytes.NewBuffer(data))
		if err != nil {
			return nil, err
		}
		req = req.WithContext(ctx)
		req.Header.Set("Content-Type", "application/json")
		c.addAuth(req)
		tracer.Start(req)
		return c.client.Do(req)
	}))
}
func (c *Client) Delete(ctx context.Context, endpoint string) (*Response, error) {
	if c.sanitizerEnabled {
		err := isPathSafe(endpoint)
		if err != nil {
			return nil, err
		}
	}
	tracer := c.newTracer()
	return tracer.Done(c.RoundTrip(func() (*http.Response, error) {
		req, err := http.NewRequest(http.MethodDelete, endpoint, nil)
		if err != nil {
			return nil, err
		}
		req = req.WithContext(ctx)
		c.addAuth(req)
		tracer.Start(req)
		return c.client.Do(req)
	}))
}
func (c *Client) DeleteWithParams(ctx context.Context, endpoint string, params url.Values) (*Response, error) {
	baseURL, err := url.Parse(endpoint)
	if err != nil {
		return nil, err
	}
	baseURL.RawQuery = params.Encode()
	return c.Delete(ctx, baseURL.String())
}