func (a *API) PerformRequest(req *http.Request) (*http.Response, error) {
	if a.Auth != nil {
		if err := a.Auth.Sign(req); err != nil {
			return nil, err
		}
	}
	resp, err := a.Client.Do(req)
	if err != nil {
		return nil, err
	}
	return resp, err
}
PerformRequest logs the request, dumping its content if required then makes the request and logs
and dumps the corresponding response.
package rsapi
import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"net/url"
	"strconv"
	"github.com/rightscale/rsc/metadata"
)
type FileUpload struct {
	Name     string     
	Filename string     
	Reader   io.Reader  
}
func (f *FileUpload) MarshalJSON() ([]byte, error) {
	b, err := ioutil.ReadAll(f.Reader)
	if err != nil {
		return nil, err
	}
	return json.Marshal(string(b))
}
type SourceUpload struct {
	Reader io.Reader
}
func extractUploads(payload *APIParams) (uploads []*FileUpload) {
	for k, v := range *payload {
		if mpart, ok := v.(*FileUpload); ok {
			uploads = append(uploads, mpart)
			delete(*payload, k)
		} else if child_params, ok := v.(APIParams); ok {
			child_uploads := extractUploads(&child_params)
			uploads = append(uploads, child_uploads...)
		}
	}
	return uploads
}
func extractSourceUpload(payload *APIParams) *SourceUpload {
	var sourceUpload *SourceUpload
	for k, v := range *payload {
		if mpart, ok := v.(*SourceUpload); ok {
			sourceUpload = mpart
			delete(*payload, k)
		}
	}
	return sourceUpload
}
func writeMultipartParams(w *multipart.Writer, payload APIParams, prefix string) error {
	for k, v := range payload {
		fieldName := k
		if prefix != "" {
			fieldName = fmt.Sprintf("%s[%s]", prefix, k)
		}
		switch v.(type) {
		case string:
			err := w.WriteField(fieldName, v.(string))
			if err != nil {
				return err
			}
		case APIParams:
			err := writeMultipartParams(w, v.(APIParams), fieldName)
			if err != nil {
				return err
			}
		default:
			return fmt.Errorf("Unknown type for multipart form section %s: %#v", fieldName, v)
		}
	}
	return nil
}
func (a *API) BuildHTTPRequest(verb, path, version string, params, payload APIParams) (*http.Request, error) {
	u := url.URL{Host: a.Host, Path: path}
	if params != nil {
		var values = u.Query()
		for n, p := range params {
			switch t := p.(type) {
			case string:
				values.Set(n, t)
			case int:
				values.Set(n, strconv.Itoa(t))
			case bool:
				values.Set(n, strconv.FormatBool(t))
			case []string:
				for _, e := range t {
					values.Add(n, e)
				}
			case []int:
				for _, e := range t {
					values.Add(n, strconv.Itoa(e))
				}
			case []bool:
				for _, e := range t {
					values.Add(n, strconv.FormatBool(e))
				}
			case []interface{}:
				for _, e := range t {
					values.Add(n, fmt.Sprintf("%v", e))
				}
			case map[string]string:
				for pn, e := range t {
					values.Add(fmt.Sprintf("%s[%s]", n, pn), e)
				}
			default:
				return nil, fmt.Errorf("Invalid param value <%+v> for %s, value must be a string, an integer, a bool, an array of these types of a map of strings", p, n)
			}
		}
		u.RawQuery = values.Encode()
	}
	var jsonBytes []byte
	var body io.Reader
	var isMultipart bool
	var isSourceUpload bool
	var boundary string
	if payload != nil {
		var fields io.Reader
		var multiPartUploads []*FileUpload
		if a.FileEncoding == FileEncodingMime {
			multiPartUploads = extractUploads(&payload)
			isMultipart = len(multiPartUploads) > 0
		}
		sourceUpload := extractSourceUpload(&payload)
		if len(payload) > 0 {
			var err error
			if jsonBytes, err = json.Marshal(payload); err != nil {
				return nil, fmt.Errorf("failed to serialize request body: %s", err.Error())
			}
			fields = bytes.NewBuffer(jsonBytes)
		}
		if isMultipart {
			var buffer bytes.Buffer
			w := multipart.NewWriter(&buffer)
			if len(payload) > 0 {
				err := writeMultipartParams(w, payload, "")
				if err != nil {
					return nil, fmt.Errorf("failed to write multipart params: %s", err.Error())
				}
			}
			for _, u := range multiPartUploads {
				p, err := w.CreateFormFile(u.Name, u.Filename)
				if err != nil {
					return nil, fmt.Errorf("failed to create multipart file: %s", err.Error())
				}
				_, err = io.Copy(p, u.Reader)
				if err != nil {
					return nil, fmt.Errorf("failed to copy multipart file: %s", err.Error())
				}
			}
			if err := w.Close(); err != nil {
				return nil, fmt.Errorf("failed to close multipart body: %s", err.Error())
			}
			boundary = w.Boundary()
			body = &buffer
		} else if sourceUpload != nil {
			isSourceUpload = true
			body = sourceUpload.Reader
		} else {
			body = fields
		}
	}
	var req, err = http.NewRequest(verb, u.String(), body)
	if err != nil {
		return nil, err
	}
	if version != "" {
		if a.VersionHeader != "" {
			req.Header.Set(a.VersionHeader, version)
		} else {
			req.Header.Set("X-Api-Version", version)
		}
	}
	if isMultipart {
		req.Header.Set("Content-Type", fmt.Sprintf("multipart/form-data; boundary=%s", boundary))
	} else if isSourceUpload {
		req.Header.Set("Content-Type", "text/plain")
	} else {
		req.Header.Set("Content-Type", "application/json")
	}
	return req, nil
}