github.com/crosbymichael/octokat@v0.0.0-20160826194511-076a32289ed5/client.go (about)

     1  package octokat
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"net/url"
    10  	"strings"
    11  )
    12  
    13  type Client struct {
    14  	httpClient *http.Client
    15  	BaseURL    string
    16  	Login      string
    17  	Password   string
    18  	Token      string
    19  }
    20  
    21  func (c *Client) WithHTTPClient(httpClient *http.Client) *Client {
    22  	c.httpClient = httpClient
    23  	return c
    24  }
    25  
    26  func (c *Client) WithLogin(login, password string) *Client {
    27  	c.Login = login
    28  	c.Password = password
    29  	return c
    30  }
    31  
    32  func (c *Client) WithToken(token string) *Client {
    33  	c.Token = token
    34  	return c
    35  }
    36  
    37  func (c *Client) get(path string, headers Headers) ([]byte, error) {
    38  	return c.request("GET", path, headers, nil)
    39  }
    40  
    41  func (c *Client) post(path string, headers Headers, content io.Reader) ([]byte, error) {
    42  	return c.request("POST", path, headers, content)
    43  }
    44  
    45  func (c *Client) patch(path string, headers Headers, content io.Reader) ([]byte, error) {
    46  	return c.request("PATCH", path, headers, content)
    47  }
    48  
    49  func (c *Client) put(path string, headers Headers, content io.Reader) ([]byte, error) {
    50  	return c.request("PUT", path, headers, content)
    51  }
    52  
    53  func (c *Client) delete(path string, headers Headers) error {
    54  	_, err := c.request("DELETE", path, headers, nil)
    55  	return err
    56  }
    57  
    58  func (c *Client) jsonGet(path string, options *Options, v interface{}) error {
    59  	var headers Headers
    60  	if options != nil {
    61  		headers = options.Headers
    62  
    63  		if options.QueryParams != nil {
    64  			params := url.Values{}
    65  			for k, v := range options.QueryParams {
    66  				params.Set(k, v)
    67  			}
    68  			if strings.Contains(path, "?") {
    69  				path = fmt.Sprintf("%s&%s", path, params.Encode())
    70  			} else {
    71  				path = fmt.Sprintf("%s?%s", path, params.Encode())
    72  			}
    73  		}
    74  	}
    75  
    76  	body, err := c.get(path, headers)
    77  	if err != nil {
    78  		return err
    79  	}
    80  
    81  	return jsonUnmarshal(body, v)
    82  }
    83  
    84  func (c *Client) jsonPost(path string, options *Options, v interface{}) error {
    85  	var headers Headers
    86  	if options != nil {
    87  		headers = options.Headers
    88  	}
    89  
    90  	var buffer *bytes.Buffer
    91  	if options != nil && options.Params != nil {
    92  		b, err := jsonMarshal(options.Params)
    93  		if err != nil {
    94  			return err
    95  		}
    96  
    97  		buffer = bytes.NewBuffer(b)
    98  	}
    99  
   100  	// *bytes.Buffer(nil) != nil
   101  	// see http://golang.org/doc/faq#nil_error
   102  	var content io.Reader
   103  	if buffer == nil {
   104  		content = nil
   105  	} else {
   106  		content = buffer
   107  	}
   108  
   109  	body, err := c.post(path, headers, content)
   110  	if err != nil {
   111  		return err
   112  	}
   113  
   114  	return jsonUnmarshal(body, v)
   115  }
   116  
   117  func (c *Client) jsonPut(path string, options *Options, v interface{}) error {
   118  	var headers Headers
   119  	if options != nil {
   120  		headers = options.Headers
   121  	}
   122  
   123  	var buffer *bytes.Buffer
   124  	if options != nil && options.Params != nil {
   125  		b, err := jsonMarshal(options.Params)
   126  		if err != nil {
   127  			return err
   128  		}
   129  
   130  		buffer = bytes.NewBuffer(b)
   131  	}
   132  
   133  	// *bytes.Buffer(nil) != nil
   134  	// see http://golang.org/doc/faq#nil_error
   135  	var content io.Reader
   136  	if buffer == nil {
   137  		content = nil
   138  	} else {
   139  		content = buffer
   140  	}
   141  
   142  	body, err := c.put(path, headers, content)
   143  	if err != nil {
   144  		return err
   145  	}
   146  
   147  	return jsonUnmarshal(body, v)
   148  
   149  }
   150  
   151  func (c *Client) jsonPatch(path string, options *Options, v interface{}) error {
   152  	var headers Headers
   153  	if options != nil {
   154  		headers = options.Headers
   155  	}
   156  
   157  	var buffer *bytes.Buffer
   158  	if options != nil && options.Params != nil {
   159  		b, err := jsonMarshal(options.Params)
   160  		if err != nil {
   161  			return err
   162  		}
   163  
   164  		buffer = bytes.NewBuffer(b)
   165  	}
   166  
   167  	// *bytes.Buffer(nil) != nil
   168  	// see http://golang.org/doc/faq#nil_error
   169  	var content io.Reader
   170  	if buffer == nil {
   171  		content = nil
   172  	} else {
   173  		content = buffer
   174  	}
   175  
   176  	body, err := c.patch(path, headers, content)
   177  	if err != nil {
   178  		return err
   179  	}
   180  
   181  	return jsonUnmarshal(body, v)
   182  
   183  }
   184  
   185  func (c *Client) request(method, path string, headers Headers, content io.Reader) ([]byte, error) {
   186  	url, err := c.buildURL(path)
   187  	if err != nil {
   188  		return nil, err
   189  	}
   190  
   191  	request, err := http.NewRequest(method, url.String(), content)
   192  	if err != nil {
   193  		return nil, err
   194  	}
   195  
   196  	c.setDefaultHeaders(request)
   197  
   198  	if headers != nil {
   199  		for h, v := range headers {
   200  			request.Header.Set(h, v)
   201  		}
   202  	}
   203  
   204  	response, err := c.httpClient.Do(request)
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  
   209  	body, err := ioutil.ReadAll(response.Body)
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  
   214  	if response.StatusCode >= 400 && response.StatusCode < 600 {
   215  		return nil, handleErrors(body)
   216  	}
   217  
   218  	return body, nil
   219  }
   220  
   221  func (c *Client) buildURL(pathOrURL string) (*url.URL, error) {
   222  	u, e := url.ParseRequestURI(pathOrURL)
   223  	if e != nil {
   224  		u, e = url.Parse(c.BaseURL)
   225  		if e != nil {
   226  			return nil, e
   227  		}
   228  
   229  		return u.Parse(pathOrURL)
   230  	}
   231  
   232  	return u, nil
   233  }
   234  
   235  func (c *Client) setDefaultHeaders(request *http.Request) {
   236  	request.Header.Set("Accept", MediaType)
   237  	request.Header.Set("User-Agent", UserAgent)
   238  	request.Header.Set("Content-Type", DefaultContentType)
   239  	if c.isBasicAuth() {
   240  		request.Header.Set("Authorization", fmt.Sprintf("Basic %s", hashAuth(c.Login, c.Password)))
   241  	} else if c.isTokenAuth() {
   242  		request.Header.Set("Authorization", fmt.Sprintf("token %s", c.Token))
   243  	}
   244  }
   245  
   246  func (c *Client) isBasicAuth() bool {
   247  	return c.Login != "" && c.Password != ""
   248  }
   249  
   250  func (c *Client) isTokenAuth() bool {
   251  	return c.Token != ""
   252  }