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 }