123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- package apiclient
- import (
- "bytes"
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/http/httputil"
- "net/url"
- "strings"
- log "github.com/sirupsen/logrus"
- )
- func (c *ApiClient) NewRequest(method, url string, body interface{}) (*http.Request, error) {
- if !strings.HasSuffix(c.BaseURL.Path, "/") {
- return nil, fmt.Errorf("BaseURL must have a trailing slash, but %q does not", c.BaseURL)
- }
- u, err := c.BaseURL.Parse(url)
- if err != nil {
- return nil, err
- }
- var buf io.ReadWriter
- if body != nil {
- buf = &bytes.Buffer{}
- enc := json.NewEncoder(buf)
- enc.SetEscapeHTML(false)
- err := enc.Encode(body)
- if err != nil {
- return nil, err
- }
- }
- req, err := http.NewRequest(method, u.String(), buf)
- if err != nil {
- return nil, err
- }
- if body != nil {
- req.Header.Set("Content-Type", "application/json")
- }
- return req, nil
- }
- func (c *ApiClient) Do(ctx context.Context, req *http.Request, v interface{}) (*Response, error) {
- if ctx == nil {
- return nil, errors.New("context must be non-nil")
- }
- req = req.WithContext(ctx)
- // Check rate limit
- if c.UserAgent != "" {
- req.Header.Add("User-Agent", c.UserAgent)
- }
- resp, err := c.client.Do(req)
- if resp != nil && resp.Body != nil {
- defer resp.Body.Close()
- }
- if err != nil {
- // If we got an error, and the context has been canceled,
- // the context's error is probably more useful.
- select {
- case <-ctx.Done():
- return nil, ctx.Err()
- default:
- }
- // If the error type is *url.Error, sanitize its URL before returning.
- if e, ok := err.(*url.Error); ok {
- if url, err := url.Parse(e.URL); err == nil {
- e.URL = url.String()
- return newResponse(resp), e
- } else {
- return newResponse(resp), err
- }
- }
- return newResponse(resp), err
- }
- for k, v := range resp.Header {
- log.Debugf("[headers] %s : %s", k, v)
- }
- dump, err := httputil.DumpResponse(resp, true)
- if err == nil {
- log.Debugf("Response: %s", string(dump))
- }
- response := newResponse(resp)
- err = CheckResponse(resp)
- if err != nil {
- return response, err
- }
- if v != nil {
- if w, ok := v.(io.Writer); ok {
- io.Copy(w, resp.Body)
- } else {
- decErr := json.NewDecoder(resp.Body).Decode(v)
- if decErr == io.EOF {
- decErr = nil // ignore EOF errors caused by empty response body
- }
- if decErr != nil {
- err = decErr
- }
- }
- }
- return response, err
- }
|