ref(client): add wrappers for method chaining

pull/419/head
Adam Reese 9 years ago
parent f382c70fb6
commit c3aaa8b56e

@ -44,7 +44,6 @@ type Client struct {
Transport http.RoundTripper Transport http.RoundTripper
// Debug enables http logging // Debug enables http logging
Debug bool Debug bool
// Base URL for remote service // Base URL for remote service
baseURL *url.URL baseURL *url.URL
} }
@ -99,12 +98,59 @@ func (c *Client) agent() string {
return fmt.Sprintf("helm/%s", version.Version) return fmt.Sprintf("helm/%s", version.Version)
} }
func (c *Client) Get(endpoint string, v interface{}) error { // Get calls GET on an endpoint and decodes the response
return c.CallService(endpoint, "GET", &v, nil) func (c *Client) Get(endpoint string, v interface{}) (*Response, error) {
return c.Exec(c.NewRequest("GET", endpoint, nil), &v)
}
// Delete calls DELETE on an endpoint and decodes the response
func (c *Client) Delete(endpoint string, v interface{}) (*Response, error) {
return c.Exec(c.NewRequest("DELETE", endpoint, nil), &v)
}
// NewRequest creates a new client request
func (c *Client) NewRequest(method, endpoint string, body io.Reader) *Request {
u, err := c.url(endpoint)
if err != nil {
return &Request{err: err}
}
req, err := http.NewRequest(method, u, body)
req.Header.Set("User-Agent", c.agent())
req.Header.Set("Accept", "application/json")
return &Request{req, err}
}
// Exec sends a request and decodes the response
func (c *Client) Exec(req *Request, v interface{}) (*Response, error) {
return c.Result(c.Do(req), &v)
} }
func (c *Client) Delete(endpoint string, v interface{}) error { // Result checks status code and decodes a response body
return c.CallService(endpoint, "DELETE", &v, nil) func (c *Client) Result(resp *Response, v interface{}) (*Response, error) {
switch {
case resp.err != nil:
return resp, resp
case resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices:
return resp, resp.HTTPError()
}
return resp, decodeResponse(resp, v)
}
// Do send a request and returns a response
func (c *Client) Do(req *Request) *Response {
if req.err != nil {
return &Response{err: req}
}
client := &http.Client{
Timeout: c.HTTPTimeout,
Transport: c.transport(),
}
resp, err := client.Do(req.Request)
return &Response{resp, err}
} }
// CallService is a low-level function for making an API call. // CallService is a low-level function for making an API call.
@ -130,7 +176,6 @@ func (c *Client) CallService(path, method string, dest interface{}, reader io.Re
func (c *Client) callHTTP(path, method string, reader io.Reader) (string, error) { func (c *Client) callHTTP(path, method string, reader io.Reader) (string, error) {
request, err := http.NewRequest(method, path, reader) request, err := http.NewRequest(method, path, reader)
// TODO: dynamically set version
request.Header.Set("User-Agent", c.agent()) request.Header.Set("User-Agent", c.agent())
request.Header.Set("Accept", "application/json") request.Header.Set("Accept", "application/json")
request.Header.Add("Content-Type", "application/json") request.Header.Add("Content-Type", "application/json")
@ -183,6 +228,42 @@ func DefaultServerURL(host string) (*url.URL, error) {
return hostURL, nil return hostURL, nil
} }
// Request wraps http.Request to include error
type Request struct {
*http.Request
err error
}
// Error implements the error interface.
func (r *Request) Error() string {
return fmt.Sprint("%s", r.err)
}
// Response wraps http.Response to include error
type Response struct {
*http.Response
err error
}
// Error implements the error interface.
func (r *Response) Error() string {
return fmt.Sprint("%s", r.err)
}
// HTTPError creates a new HTTPError from response
func (r *Response) HTTPError() error {
defer r.Body.Close()
body, err := ioutil.ReadAll(r.Body)
if err != nil {
return err
}
return &HTTPError{
StatusCode: r.StatusCode,
Message: string(body),
URL: r.Request.URL,
}
}
// HTTPError is an error caused by an unexpected HTTP status code. // HTTPError is an error caused by an unexpected HTTP status code.
// //
// The StatusCode will not necessarily be a 4xx or 5xx. Any unexpected code // The StatusCode will not necessarily be a 4xx or 5xx. Any unexpected code
@ -202,3 +283,14 @@ func (e *HTTPError) Error() string {
func (e *HTTPError) String() string { func (e *HTTPError) String() string {
return e.Error() return e.Error()
} }
func decodeResponse(resp *Response, v interface{}) error {
defer resp.Body.Close()
if resp.Body == nil {
return nil
}
if err := json.NewDecoder(resp.Body).Decode(v); err != nil {
return fmt.Errorf("Failed to parse JSON response from service")
}
return nil
}

@ -32,7 +32,7 @@ import (
// ListDeployments lists the deployments in DM. // ListDeployments lists the deployments in DM.
func (c *Client) ListDeployments() ([]string, error) { func (c *Client) ListDeployments() ([]string, error) {
var l []string var l []string
err := c.Get("deployments", &l) _, err := c.Get("deployments", &l)
return l, err return l, err
} }
@ -91,14 +91,14 @@ func (c *Client) PostChart(filename, deployname string) (string, error) {
// GetDeployment retrieves the supplied deployment // GetDeployment retrieves the supplied deployment
func (c *Client) GetDeployment(name string) (*common.Deployment, error) { func (c *Client) GetDeployment(name string) (*common.Deployment, error) {
var deployment *common.Deployment var deployment *common.Deployment
err := c.Get(fancypath.Join("deployments", name), &deployment) _, err := c.Get(fancypath.Join("deployments", name), &deployment)
return deployment, err return deployment, err
} }
// DeleteDeployment deletes the supplied deployment // DeleteDeployment deletes the supplied deployment
func (c *Client) DeleteDeployment(name string) (*common.Deployment, error) { func (c *Client) DeleteDeployment(name string) (*common.Deployment, error) {
var deployment *common.Deployment var deployment *common.Deployment
err := c.Delete(filepath.Join("deployments", name), &deployment) _, err := c.Delete(filepath.Join("deployments", name), &deployment)
return deployment, err return deployment, err
} }

Loading…
Cancel
Save