client/api/api_client.go
func (c Client) RequestContext(ctx context.Context, method, path string, query url.Values, body io.Reader, accept []string) (resp *http.Response, err error) {
	if !strings.HasPrefix(c.Endpoint, "http://") && !strings.HasPrefix(c.Endpoint, "https://") {
		c.Endpoint = "http://" + c.Endpoint
	}
	u, err := url.Parse(c.Endpoint)
	if err != nil {
		return
	}
	u.Path += path

	u.RawQuery = query.Encode()
	req, err := http.NewRequest(method, u.String(), body)
	if err != nil {
		return
	}
	if ctx != nil {
		req = req.WithContext(ctx)
	}
	for _, a := range accept {
		req.Header.Add("Accept", a)
	}
	if c.UserAgent != "" {
		req.Header.Set("User-Agent", c.UserAgent)
	}
	for key, value := range c.Headers {
		req.Header.Set(key, value)
	}
	if c.Key != "" {
		keyHeader := c.KeyHeader
		if keyHeader == "" {
			keyHeader = DefaultKeyHeader
		}
		req.Header.Set(keyHeader, c.Key)
	}
	if c.BasicAuth != nil {
		req.SetBasicAuth(c.BasicAuth.Username, c.BasicAuth.Password)
	}

	httpClient := c.HTTPClient
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	resp, err = httpClient.Do(req)
	if err != nil {
		return
	}

	if 200 > resp.StatusCode || resp.StatusCode >= 300 {
		defer func() {
			io.Copy(ioutil.Discard, resp.Body)
			resp.Body.Close()
		}()

		message := struct {
			Message string `json:"message"`
			Code    *int   `json:"code"`
		}{}
		var body []byte
		body, err = ioutil.ReadAll(resp.Body)
		if err != nil {
			return
		}
		if resp.ContentLength != 0 && strings.Contains(resp.Header.Get("Content-Type"), "application/json") {
			if err = json.Unmarshal(body, &message); err != nil {
				switch e := err.(type) {
				case *json.SyntaxError:
					line, col := getLineColFromOffset(body, e.Offset)
					message.Message = fmt.Sprintf("json %s, line: %d, column: %d", e, line, col)
				case *json.UnmarshalTypeError:
					// If the type of message is not as expected,
					// continue with http based error reporting.
				default:
					return
				}
			}
		}
		if message.Code != nil && c.ErrorRegistry != nil {
			if err = c.ErrorRegistry.Error(*message.Code); err != nil {
				return
			}
			if handler := c.ErrorRegistry.Handler(*message.Code); handler != nil {
				err = handler(body)
				return
			}
		}
		var msg string
		if message.Message != "" {
			msg = message.Message
		} else {
			msg = "http status: " + strings.ToLower(http.StatusText(resp.StatusCode))
		}
		err = &Error{
			Message: msg,
			Code:    resp.StatusCode,
		}
	}

	return
}
func (c Client) RequestContext(ctx context.Context, method, path string, query url.Values, body io.Reader, accept []string) (resp *http.Response, err error) {
	if !strings.HasPrefix(c.Endpoint, "http://") && !strings.HasPrefix(c.Endpoint, "https://") {
		c.Endpoint = "http://" + c.Endpoint
	}
	u, err := url.Parse(c.Endpoint)
	if err != nil {
		return
	}
	u.Path += path

	u.RawQuery = query.Encode()
	req, err := http.NewRequest(method, u.String(), body)
	if err != nil {
		return
	}
	if ctx != nil {
		req = req.WithContext(ctx)
	}
	for _, a := range accept {
		req.Header.Add("Accept", a)
	}
	if c.UserAgent != "" {
		req.Header.Set("User-Agent", c.UserAgent)
	}
	for key, value := range c.Headers {
		req.Header.Set(key, value)
	}
	if c.Key != "" {
		keyHeader := c.KeyHeader
		if keyHeader == "" {
			keyHeader = DefaultKeyHeader
		}
		req.Header.Set(keyHeader, c.Key)
	}
	if c.BasicAuth != nil {
		req.SetBasicAuth(c.BasicAuth.Username, c.BasicAuth.Password)
	}

	httpClient := c.HTTPClient
	if httpClient == nil {
		httpClient = http.DefaultClient
	}
	resp, err = httpClient.Do(req)
	if err != nil {
		return
	}

	if 200 > resp.StatusCode || resp.StatusCode >= 300 {
		defer func() {
			io.Copy(ioutil.Discard, resp.Body)
			resp.Body.Close()
		}()

		message := struct {
			Message string `json:"message"`
			Code    *int   `json:"code"`
		}{}
		var body []byte
		body, err = ioutil.ReadAll(resp.Body)
		if err != nil {
			return
		}
		if resp.ContentLength != 0 && strings.Contains(resp.Header.Get("Content-Type"), "application/json") {
			if err = json.Unmarshal(body, &message); err != nil {
				switch e := err.(type) {
				case *json.SyntaxError:
					line, col := getLineColFromOffset(body, e.Offset)
					message.Message = fmt.Sprintf("json %s, line: %d, column: %d", e, line, col)
				case *json.UnmarshalTypeError:
					// If the type of message is not as expected,
					// continue with http based error reporting.
				default:
					return
				}
			}
		}
		if message.Code != nil && c.ErrorRegistry != nil {
			if err = c.ErrorRegistry.Error(*message.Code); err != nil {
				return
			}
			if handler := c.ErrorRegistry.Handler(*message.Code); handler != nil {
				err = handler(body)
				return
			}
		}
		var msg string
		if message.Message != "" {
			msg = message.Message
		} else {
			msg = "http status: " + strings.ToLower(http.StatusText(resp.StatusCode))
		}
		err = &Error{
			Message: msg,
			Code:    resp.StatusCode,
		}
	}

	return
}
// RequestContext provides the same functionality as Request with Context instance passing to http.Request.