packer-cn/builder/oracle/oci/client/base_client.go

216 lines
4.8 KiB
Go

package oci
import (
"bytes"
"encoding/json"
"github.com/google/go-querystring/query"
"net/http"
"net/url"
)
const (
contentType = "Content-Type"
jsonContentType = "application/json"
)
// baseClient provides a basic (AND INTENTIONALLY INCOMPLETE) JSON REST client
// that abstracts away some of the repetitive code required in the OCI Client.
type baseClient struct {
httpClient *http.Client
method string
url string
queryStruct interface{}
header http.Header
body interface{}
}
// newBaseClient constructs a default baseClient.
func newBaseClient() *baseClient {
return &baseClient{
httpClient: http.DefaultClient,
method: "GET",
header: make(http.Header),
}
}
// New creates a copy of an existing baseClient.
func (c *baseClient) New() *baseClient {
// Copy headers
header := make(http.Header)
for k, v := range c.header {
header[k] = v
}
return &baseClient{
httpClient: c.httpClient,
method: c.method,
url: c.url,
header: header,
}
}
// Client sets the http Client used to perform requests.
func (c *baseClient) Client(httpClient *http.Client) *baseClient {
if httpClient == nil {
c.httpClient = http.DefaultClient
} else {
c.httpClient = httpClient
}
return c
}
// Base sets the base client url.
func (c *baseClient) Base(path string) *baseClient {
c.url = path
return c
}
// Path extends the client url.
func (c *baseClient) Path(path string) *baseClient {
baseURL, baseErr := url.Parse(c.url)
pathURL, pathErr := url.Parse(path)
// Bail on parsing error leaving the client's url unmodified
if baseErr != nil || pathErr != nil {
return c
}
c.url = baseURL.ResolveReference(pathURL).String()
return c
}
// QueryStruct sets the struct from which the request querystring is built.
func (c *baseClient) QueryStruct(params interface{}) *baseClient {
c.queryStruct = params
return c
}
// SetBody wraps a given struct for serialisation and sets the client body.
func (c *baseClient) SetBody(params interface{}) *baseClient {
c.body = params
return c
}
// Header
// AddHeader adds a HTTP header to the client. Existing keys will be extended.
func (c *baseClient) AddHeader(key, value string) *baseClient {
c.header.Add(key, value)
return c
}
// SetHeader sets a HTTP header on the client. Existing keys will be
// overwritten.
func (c *baseClient) SetHeader(key, value string) *baseClient {
c.header.Add(key, value)
return c
}
// HTTP methods (subset)
// Get sets the client's HTTP method to GET.
func (c *baseClient) Get(path string) *baseClient {
c.method = "GET"
return c.Path(path)
}
// Post sets the client's HTTP method to POST.
func (c *baseClient) Post(path string) *baseClient {
c.method = "POST"
return c.Path(path)
}
// Delete sets the client's HTTP method to DELETE.
func (c *baseClient) Delete(path string) *baseClient {
c.method = "DELETE"
return c.Path(path)
}
// Do executes a HTTP request and returns the response encoded as either error
// or success values.
func (c *baseClient) Do(req *http.Request, successV, failureV interface{}) (*http.Response, error) {
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
if successV != nil {
err = json.NewDecoder(resp.Body).Decode(successV)
}
} else {
if failureV != nil {
err = json.NewDecoder(resp.Body).Decode(failureV)
}
}
return resp, err
}
// Request builds a http.Request from the baseClient instance.
func (c *baseClient) Request() (*http.Request, error) {
reqURL, err := url.Parse(c.url)
if err != nil {
return nil, err
}
if c.queryStruct != nil {
err = addQueryStruct(reqURL, c.queryStruct)
if err != nil {
return nil, err
}
}
body := &bytes.Buffer{}
if c.body != nil {
if err := json.NewEncoder(body).Encode(c.body); err != nil {
return nil, err
}
}
req, err := http.NewRequest(c.method, reqURL.String(), body)
if err != nil {
return nil, err
}
// Add headers to request
for k, vs := range c.header {
for _, v := range vs {
req.Header.Add(k, v)
}
}
return req, nil
}
// Recieve creates a http request from the client and executes it returning the
// response.
func (c *baseClient) Receive(successV, failureV interface{}) (*http.Response, error) {
req, err := c.Request()
if err != nil {
return nil, err
}
return c.Do(req, successV, failureV)
}
// addQueryStruct converts a struct to a querystring and merges any values
// provided in the URL itself.
func addQueryStruct(reqURL *url.URL, queryStruct interface{}) error {
urlValues, err := url.ParseQuery(reqURL.RawQuery)
if err != nil {
return err
}
queryValues, err := query.Values(queryStruct)
if err != nil {
return err
}
for k, vs := range queryValues {
for _, v := range vs {
urlValues.Add(k, v)
}
}
reqURL.RawQuery = urlValues.Encode()
return nil
}