github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/oracle/oci/client/base_client.go (about)

     1  package oci
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"github.com/google/go-querystring/query"
     7  	"net/http"
     8  	"net/url"
     9  )
    10  
    11  const (
    12  	contentType     = "Content-Type"
    13  	jsonContentType = "application/json"
    14  )
    15  
    16  // baseClient provides a basic (AND INTENTIONALLY INCOMPLETE) JSON REST client
    17  // that abstracts away some of the repetitive code required in the OCI Client.
    18  type baseClient struct {
    19  	httpClient  *http.Client
    20  	method      string
    21  	url         string
    22  	queryStruct interface{}
    23  	header      http.Header
    24  	body        interface{}
    25  }
    26  
    27  // newBaseClient constructs a default baseClient.
    28  func newBaseClient() *baseClient {
    29  	return &baseClient{
    30  		httpClient: http.DefaultClient,
    31  		method:     "GET",
    32  		header:     make(http.Header),
    33  	}
    34  }
    35  
    36  // New creates a copy of an existing baseClient.
    37  func (c *baseClient) New() *baseClient {
    38  	// Copy headers
    39  	header := make(http.Header)
    40  	for k, v := range c.header {
    41  		header[k] = v
    42  	}
    43  
    44  	return &baseClient{
    45  		httpClient: c.httpClient,
    46  		method:     c.method,
    47  		url:        c.url,
    48  		header:     header,
    49  	}
    50  }
    51  
    52  // Client sets the http Client used to perform requests.
    53  func (c *baseClient) Client(httpClient *http.Client) *baseClient {
    54  	if httpClient == nil {
    55  		c.httpClient = http.DefaultClient
    56  	} else {
    57  		c.httpClient = httpClient
    58  	}
    59  	return c
    60  }
    61  
    62  // Base sets the base client url.
    63  func (c *baseClient) Base(path string) *baseClient {
    64  	c.url = path
    65  	return c
    66  }
    67  
    68  // Path extends the client url.
    69  func (c *baseClient) Path(path string) *baseClient {
    70  	baseURL, baseErr := url.Parse(c.url)
    71  	pathURL, pathErr := url.Parse(path)
    72  	// Bail on parsing error leaving the client's url unmodified
    73  	if baseErr != nil || pathErr != nil {
    74  		return c
    75  	}
    76  
    77  	c.url = baseURL.ResolveReference(pathURL).String()
    78  	return c
    79  }
    80  
    81  // QueryStruct sets the struct from which the request querystring is built.
    82  func (c *baseClient) QueryStruct(params interface{}) *baseClient {
    83  	c.queryStruct = params
    84  	return c
    85  }
    86  
    87  // SetBody wraps a given struct for serialisation and sets the client body.
    88  func (c *baseClient) SetBody(params interface{}) *baseClient {
    89  	c.body = params
    90  	return c
    91  }
    92  
    93  // Header
    94  
    95  // AddHeader adds a HTTP header to the client. Existing keys will be extended.
    96  func (c *baseClient) AddHeader(key, value string) *baseClient {
    97  	c.header.Add(key, value)
    98  	return c
    99  }
   100  
   101  // SetHeader sets a HTTP header on the client. Existing keys will be
   102  // overwritten.
   103  func (c *baseClient) SetHeader(key, value string) *baseClient {
   104  	c.header.Add(key, value)
   105  	return c
   106  }
   107  
   108  // HTTP methods (subset)
   109  
   110  // Get sets the client's HTTP method to GET.
   111  func (c *baseClient) Get(path string) *baseClient {
   112  	c.method = "GET"
   113  	return c.Path(path)
   114  }
   115  
   116  // Post sets the client's HTTP method to POST.
   117  func (c *baseClient) Post(path string) *baseClient {
   118  	c.method = "POST"
   119  	return c.Path(path)
   120  }
   121  
   122  // Delete sets the client's HTTP method to DELETE.
   123  func (c *baseClient) Delete(path string) *baseClient {
   124  	c.method = "DELETE"
   125  	return c.Path(path)
   126  }
   127  
   128  // Do executes a HTTP request and returns the response encoded as either error
   129  // or success values.
   130  func (c *baseClient) Do(req *http.Request, successV, failureV interface{}) (*http.Response, error) {
   131  	resp, err := c.httpClient.Do(req)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  	defer resp.Body.Close()
   136  
   137  	if resp.StatusCode >= 200 && resp.StatusCode < 300 {
   138  		if successV != nil {
   139  			err = json.NewDecoder(resp.Body).Decode(successV)
   140  		}
   141  	} else {
   142  		if failureV != nil {
   143  			err = json.NewDecoder(resp.Body).Decode(failureV)
   144  		}
   145  	}
   146  
   147  	return resp, err
   148  }
   149  
   150  // Request builds a http.Request from the baseClient instance.
   151  func (c *baseClient) Request() (*http.Request, error) {
   152  	reqURL, err := url.Parse(c.url)
   153  	if err != nil {
   154  		return nil, err
   155  	}
   156  
   157  	if c.queryStruct != nil {
   158  		err = addQueryStruct(reqURL, c.queryStruct)
   159  		if err != nil {
   160  			return nil, err
   161  		}
   162  	}
   163  
   164  	body := &bytes.Buffer{}
   165  	if c.body != nil {
   166  		if err := json.NewEncoder(body).Encode(c.body); err != nil {
   167  			return nil, err
   168  		}
   169  	}
   170  
   171  	req, err := http.NewRequest(c.method, reqURL.String(), body)
   172  	if err != nil {
   173  		return nil, err
   174  	}
   175  
   176  	// Add headers to request
   177  	for k, vs := range c.header {
   178  		for _, v := range vs {
   179  			req.Header.Add(k, v)
   180  		}
   181  	}
   182  
   183  	return req, nil
   184  }
   185  
   186  // Recieve creates a http request from the client and executes it returning the
   187  // response.
   188  func (c *baseClient) Receive(successV, failureV interface{}) (*http.Response, error) {
   189  	req, err := c.Request()
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  	return c.Do(req, successV, failureV)
   194  }
   195  
   196  // addQueryStruct converts a struct to a querystring and merges any values
   197  // provided in the URL itself.
   198  func addQueryStruct(reqURL *url.URL, queryStruct interface{}) error {
   199  	urlValues, err := url.ParseQuery(reqURL.RawQuery)
   200  	if err != nil {
   201  		return err
   202  	}
   203  	queryValues, err := query.Values(queryStruct)
   204  	if err != nil {
   205  		return err
   206  	}
   207  
   208  	for k, vs := range queryValues {
   209  		for _, v := range vs {
   210  			urlValues.Add(k, v)
   211  		}
   212  	}
   213  	reqURL.RawQuery = urlValues.Encode()
   214  	return nil
   215  }