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 }