refactor: improve http client implement
This commit is contained in:
		
							parent
							
								
									6f36998df8
								
							
						
					
					
						commit
						84946743d9
					
				| @ -21,70 +21,62 @@ import ( | |||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type ClientOption func(client *Client) error | type ClientOption func(client *Client) | ||||||
| type BeegoHttpRequestOption func(request *BeegoHTTPRequest) error | type BeegoHttpRequestOption func(request *BeegoHTTPRequest) | ||||||
| 
 | 
 | ||||||
| // WithEnableCookie will enable cookie in all subsequent request | // WithEnableCookie will enable cookie in all subsequent request | ||||||
| func WithEnableCookie(enable bool) ClientOption { | func WithEnableCookie(enable bool) ClientOption { | ||||||
| 	return func(client *Client) error { | 	return func(client *Client) { | ||||||
| 		client.Setting.EnableCookie = enable | 		client.Setting.EnableCookie = enable | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WithEnableCookie will adds UA in all subsequent request | // WithEnableCookie will adds UA in all subsequent request | ||||||
| func WithUserAgent(userAgent string) ClientOption { | func WithUserAgent(userAgent string) ClientOption { | ||||||
| 	return func(client *Client) error { | 	return func(client *Client) { | ||||||
| 		client.Setting.UserAgent = userAgent | 		client.Setting.UserAgent = userAgent | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WithTLSClientConfig will adds tls config in all subsequent request | // WithTLSClientConfig will adds tls config in all subsequent request | ||||||
| func WithTLSClientConfig(config *tls.Config) ClientOption { | func WithTLSClientConfig(config *tls.Config) ClientOption { | ||||||
| 	return func(client *Client) error { | 	return func(client *Client) { | ||||||
| 		client.Setting.TLSClientConfig = config | 		client.Setting.TLSClientConfig = config | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WithTransport will set transport field in all subsequent request | // WithTransport will set transport field in all subsequent request | ||||||
| func WithTransport(transport http.RoundTripper) ClientOption { | func WithTransport(transport http.RoundTripper) ClientOption { | ||||||
| 	return func(client *Client) error { | 	return func(client *Client) { | ||||||
| 		client.Setting.Transport = transport | 		client.Setting.Transport = transport | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WithProxy will set http proxy field in all subsequent request | // WithProxy will set http proxy field in all subsequent request | ||||||
| func WithProxy(proxy func(*http.Request) (*url.URL, error)) ClientOption { | func WithProxy(proxy func(*http.Request) (*url.URL, error)) ClientOption { | ||||||
| 	return func(client *Client) error { | 	return func(client *Client) { | ||||||
| 		client.Setting.Proxy = proxy | 		client.Setting.Proxy = proxy | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WithCheckRedirect will specifies the policy for handling redirects in all subsequent request | // WithCheckRedirect will specifies the policy for handling redirects in all subsequent request | ||||||
| func WithCheckRedirect(redirect func(req *http.Request, via []*http.Request) error) ClientOption { | func WithCheckRedirect(redirect func(req *http.Request, via []*http.Request) error) ClientOption { | ||||||
| 	return func(client *Client) error { | 	return func(client *Client) { | ||||||
| 		client.Setting.CheckRedirect = redirect | 		client.Setting.CheckRedirect = redirect | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WithHTTPSetting can replace beegoHTTPSeting | // WithHTTPSetting can replace beegoHTTPSeting | ||||||
| func WithHTTPSetting(setting BeegoHTTPSettings) ClientOption { | func WithHTTPSetting(setting BeegoHTTPSettings) ClientOption { | ||||||
| 	return func(client *Client) error { | 	return func(client *Client) { | ||||||
| 		client.Setting = &setting | 		client.Setting = setting | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WithEnableGzip will enable gzip in all subsequent request | // WithEnableGzip will enable gzip in all subsequent request | ||||||
| func WithEnableGzip(enable bool) ClientOption { | func WithEnableGzip(enable bool) ClientOption { | ||||||
| 	return func(client *Client) error { | 	return func(client *Client) { | ||||||
| 		client.Setting.Gzip = enable | 		client.Setting.Gzip = enable | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -92,73 +84,60 @@ func WithEnableGzip(enable bool) ClientOption { | |||||||
| 
 | 
 | ||||||
| // WithTimeout sets connect time out and read-write time out for BeegoRequest. | // WithTimeout sets connect time out and read-write time out for BeegoRequest. | ||||||
| func WithTimeout(connectTimeout, readWriteTimeout time.Duration) BeegoHttpRequestOption { | func WithTimeout(connectTimeout, readWriteTimeout time.Duration) BeegoHttpRequestOption { | ||||||
| 	return func(request *BeegoHTTPRequest) error { | 	return func(request *BeegoHTTPRequest) { | ||||||
| 		request.SetTimeout(connectTimeout, readWriteTimeout) | 		request.SetTimeout(connectTimeout, readWriteTimeout) | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WithHeader adds header item string in request. | // WithHeader adds header item string in request. | ||||||
| func WithHeader(key, value string) BeegoHttpRequestOption { | func WithHeader(key, value string) BeegoHttpRequestOption { | ||||||
| 	return func(request *BeegoHTTPRequest) error { | 	return func(request *BeegoHTTPRequest) { | ||||||
| 		request.Header(key, value) | 		request.Header(key, value) | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WithCookie adds a cookie to the request. | // WithCookie adds a cookie to the request. | ||||||
| func WithCookie(cookie *http.Cookie) BeegoHttpRequestOption { | func WithCookie(cookie *http.Cookie) BeegoHttpRequestOption { | ||||||
| 	return func(request *BeegoHTTPRequest) error { | 	return func(request *BeegoHTTPRequest) { | ||||||
| 		request.Header("Cookie", cookie.String()) | 		request.Header("Cookie", cookie.String()) | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Withtokenfactory adds a custom function to set Authorization | // Withtokenfactory adds a custom function to set Authorization | ||||||
| func WithTokenFactory(tokenFactory func() (string, error)) BeegoHttpRequestOption { | func WithTokenFactory(tokenFactory func() string) BeegoHttpRequestOption { | ||||||
| 	return func(request *BeegoHTTPRequest) error { | 	return func(request *BeegoHTTPRequest) { | ||||||
| 		t, err := tokenFactory() | 		t := tokenFactory() | ||||||
| 		if err != nil { | 
 | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		request.Header("Authorization", t) | 		request.Header("Authorization", t) | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WithBasicAuth adds a custom function to set basic auth | // WithBasicAuth adds a custom function to set basic auth | ||||||
| func WithBasicAuth(basicAuth func() (string, string, error)) BeegoHttpRequestOption { | func WithBasicAuth(basicAuth func() (string, string)) BeegoHttpRequestOption { | ||||||
| 	return func(request *BeegoHTTPRequest) error { | 	return func(request *BeegoHTTPRequest) { | ||||||
| 		username, password, err := basicAuth() | 		username, password := basicAuth() | ||||||
| 		if err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		request.SetBasicAuth(username, password) | 		request.SetBasicAuth(username, password) | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WithFilters will use the filter as the invocation filters | // WithFilters will use the filter as the invocation filters | ||||||
| func WithFilters(fcs ...FilterChain) BeegoHttpRequestOption { | func WithFilters(fcs ...FilterChain) BeegoHttpRequestOption { | ||||||
| 	return func(request *BeegoHTTPRequest) error { | 	return func(request *BeegoHTTPRequest) { | ||||||
| 		request.SetFilters(fcs...) | 		request.SetFilters(fcs...) | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WithContentType adds ContentType in header | // WithContentType adds ContentType in header | ||||||
| func WithContentType(contentType string) BeegoHttpRequestOption { | func WithContentType(contentType string) BeegoHttpRequestOption { | ||||||
| 	return func(request *BeegoHTTPRequest) error { | 	return func(request *BeegoHTTPRequest) { | ||||||
| 		request.Header("Content-Type", contentType) | 		request.Header(contentTypeKey, contentType) | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WithParam adds query param in to request. | // WithParam adds query param in to request. | ||||||
| func WithParam(key, value string) BeegoHttpRequestOption { | func WithParam(key, value string) BeegoHttpRequestOption { | ||||||
| 	return func(request *BeegoHTTPRequest) error { | 	return func(request *BeegoHTTPRequest) { | ||||||
| 		request.Param(key, value) | 		request.Param(key, value) | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -167,9 +146,8 @@ func WithParam(key, value string) BeegoHttpRequestOption { | |||||||
| // -1 retry indefinitely (forever) | // -1 retry indefinitely (forever) | ||||||
| // Other numbers specify the exact retry amount | // Other numbers specify the exact retry amount | ||||||
| func WithRetry(times int, delay time.Duration) BeegoHttpRequestOption { | func WithRetry(times int, delay time.Duration) BeegoHttpRequestOption { | ||||||
| 	return func(request *BeegoHTTPRequest) error { | 	return func(request *BeegoHTTPRequest) { | ||||||
| 		request.Retries(times) | 		request.Retries(times) | ||||||
| 		request.RetryDelay(delay) | 		request.RetryDelay(delay) | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -147,8 +147,8 @@ func TestOption_WithTokenFactory(t *testing.T) { | |||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| 	} | 	} | ||||||
| 	client.CommonOpts = append(client.CommonOpts, | 	client.CommonOpts = append(client.CommonOpts, | ||||||
| 		WithTokenFactory(func() (string, error) { | 		WithTokenFactory(func() string { | ||||||
| 			return "testauth", nil | 			return "testauth" | ||||||
| 		})) | 		})) | ||||||
| 
 | 
 | ||||||
| 	var str *string | 	var str *string | ||||||
| @ -172,8 +172,8 @@ func TestOption_WithBasicAuth(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| 	var str *string | 	var str *string | ||||||
| 	err = client.Get(&str, "/basic-auth/user/passwd", | 	err = client.Get(&str, "/basic-auth/user/passwd", | ||||||
| 		WithBasicAuth(func() (string, string, error) { | 		WithBasicAuth(func() (string, string) { | ||||||
| 			return "user", "passwd", nil | 			return "user", "passwd" | ||||||
| 		})) | 		})) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatal(err) | 		t.Fatal(err) | ||||||
| @ -240,7 +240,9 @@ func TestOption_WithRetry(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| 	err = client.Get(nil, "", WithRetry(retryAmount, retryDelay)) | 	err = client.Get(nil, "", WithRetry(retryAmount, retryDelay)) | ||||||
| 
 | 
 | ||||||
| 	assert.NotNil(t, err) | 	if err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
| 	endTime := time.Now().UnixNano() / int64(time.Millisecond) | 	endTime := time.Now().UnixNano() / int64(time.Millisecond) | ||||||
| 	elapsedTime := endTime - startTime | 	elapsedTime := endTime - startTime | ||||||
| 	delayedTime := int64(retryAmount) * retryDelay.Milliseconds() | 	delayedTime := int64(retryAmount) * retryDelay.Milliseconds() | ||||||
|  | |||||||
| @ -16,9 +16,6 @@ package httplib | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"strings" |  | ||||||
| 
 |  | ||||||
| 	"github.com/beego/beego/v2/core/berror" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Client provides an HTTP client supporting chain call | // Client provides an HTTP client supporting chain call | ||||||
| @ -27,8 +24,8 @@ type Client struct { | |||||||
| 	Endpoint   string | 	Endpoint   string | ||||||
| 	CommonOpts []BeegoHttpRequestOption | 	CommonOpts []BeegoHttpRequestOption | ||||||
| 
 | 
 | ||||||
| 	Setting *BeegoHTTPSettings | 	Setting BeegoHTTPSettings | ||||||
| 	pointer *responsePointer | 	pointer responsePointer | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type responsePointer struct { | type responsePointer struct { | ||||||
| @ -46,71 +43,42 @@ func NewClient(name string, endpoint string, opts ...ClientOption) (*Client, err | |||||||
| 		Endpoint: endpoint, | 		Endpoint: endpoint, | ||||||
| 	} | 	} | ||||||
| 	setting := GetDefaultSetting() | 	setting := GetDefaultSetting() | ||||||
| 	res.Setting = &setting | 	res.Setting = setting | ||||||
| 	for _, o := range opts { | 	for _, o := range opts { | ||||||
| 		err := o(res) | 		o(res) | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	return res, nil | 	return res, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Response will set response to the pointer | // Response will set response to the pointer | ||||||
| func (c *Client) Response(resp **http.Response) *Client { | func (c *Client) Response(resp **http.Response) *Client { | ||||||
| 	if c.pointer == nil { | 	newC := *c | ||||||
| 		newC := *c | 	newC.pointer.response = resp | ||||||
| 		newC.pointer = &responsePointer{ | 	return &newC | ||||||
| 			response: resp, |  | ||||||
| 		} |  | ||||||
| 		return &newC |  | ||||||
| 	} |  | ||||||
| 	c.pointer.response = resp |  | ||||||
| 	return c |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // StatusCode will set response StatusCode to the pointer | // StatusCode will set response StatusCode to the pointer | ||||||
| func (c *Client) StatusCode(code **int) *Client { | func (c *Client) StatusCode(code **int) *Client { | ||||||
| 	if c.pointer == nil { | 	newC := *c | ||||||
| 		newC := *c | 	newC.pointer.statusCode = code | ||||||
| 		newC.pointer = &responsePointer{ | 	return &newC | ||||||
| 			statusCode: code, |  | ||||||
| 		} |  | ||||||
| 		return &newC |  | ||||||
| 	} |  | ||||||
| 	c.pointer.statusCode = code |  | ||||||
| 	return c |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Headers will set response Headers to the pointer | // Headers will set response Headers to the pointer | ||||||
| func (c *Client) Headers(headers **http.Header) *Client { | func (c *Client) Headers(headers **http.Header) *Client { | ||||||
| 	if c.pointer == nil { | 	newC := *c | ||||||
| 		newC := *c | 	newC.pointer.header = headers | ||||||
| 		newC.pointer = &responsePointer{ | 	return &newC | ||||||
| 			header: headers, |  | ||||||
| 		} |  | ||||||
| 		return &newC |  | ||||||
| 	} |  | ||||||
| 	c.pointer.header = headers |  | ||||||
| 	return c |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // HeaderValue will set response HeaderValue to the pointer | // HeaderValue will set response HeaderValue to the pointer | ||||||
| func (c *Client) HeaderValue(key string, value **string) *Client { | func (c *Client) HeaderValue(key string, value **string) *Client { | ||||||
| 	if c.pointer == nil { | 	newC := *c | ||||||
| 		newC := *c | 	if newC.pointer.headerValues == nil { | ||||||
| 		newC.pointer = &responsePointer{ | 		newC.pointer.headerValues = make(map[string]**string) | ||||||
| 			headerValues: map[string]**string{ |  | ||||||
| 				key: value, |  | ||||||
| 			}, |  | ||||||
| 		} |  | ||||||
| 		return &newC |  | ||||||
| 	} | 	} | ||||||
| 	if c.pointer.headerValues == nil { | 	newC.pointer.headerValues[key] = value | ||||||
| 		c.pointer.headerValues = map[string]**string{} | 	return &newC | ||||||
| 	} |  | ||||||
| 	c.pointer.headerValues[key] = value |  | ||||||
| 	return c |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ContentType will set response ContentType to the pointer | // ContentType will set response ContentType to the pointer | ||||||
| @ -120,22 +88,13 @@ func (c *Client) ContentType(contentType **string) *Client { | |||||||
| 
 | 
 | ||||||
| // ContentLength will set response ContentLength to the pointer | // ContentLength will set response ContentLength to the pointer | ||||||
| func (c *Client) ContentLength(contentLength **int64) *Client { | func (c *Client) ContentLength(contentLength **int64) *Client { | ||||||
| 	if c.pointer == nil { | 	newC := *c | ||||||
| 		newC := *c | 	newC.pointer.contentLength = contentLength | ||||||
| 		newC.pointer = &responsePointer{ | 	return &newC | ||||||
| 			contentLength: contentLength, |  | ||||||
| 		} |  | ||||||
| 		return &newC |  | ||||||
| 	} |  | ||||||
| 	c.pointer.contentLength = contentLength |  | ||||||
| 	return c |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // setPointers set the http response value to pointer | // setPointers set the http response value to pointer | ||||||
| func (c *Client) setPointers(resp *http.Response) { | func (c *Client) setPointers(resp *http.Response) { | ||||||
| 	if c.pointer == nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	if c.pointer.response != nil { | 	if c.pointer.response != nil { | ||||||
| 		*c.pointer.response = resp | 		*c.pointer.response = resp | ||||||
| 	} | 	} | ||||||
| @ -156,36 +115,12 @@ func (c *Client) setPointers(resp *http.Response) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // initRequest will apply all the client setting, common option and request option | func (c *Client) customReq(req *BeegoHTTPRequest, opts []BeegoHttpRequestOption) { | ||||||
| func (c *Client) newRequest(method, path string, opts []BeegoHttpRequestOption) (*BeegoHTTPRequest, error) { | 	req.Setting(c.Setting) | ||||||
| 	var req *BeegoHTTPRequest | 	opts = append(c.CommonOpts, opts...) | ||||||
| 	switch method { |  | ||||||
| 	case http.MethodGet: |  | ||||||
| 		req = Get(c.Endpoint + path) |  | ||||||
| 	case http.MethodPost: |  | ||||||
| 		req = Post(c.Endpoint + path) |  | ||||||
| 	case http.MethodPut: |  | ||||||
| 		req = Put(c.Endpoint + path) |  | ||||||
| 	case http.MethodDelete: |  | ||||||
| 		req = Delete(c.Endpoint + path) |  | ||||||
| 	case http.MethodHead: |  | ||||||
| 		req = Head(c.Endpoint + path) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	req = req.Setting(*c.Setting) |  | ||||||
| 	for _, o := range c.CommonOpts { |  | ||||||
| 		err := o(req) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	for _, o := range opts { | 	for _, o := range opts { | ||||||
| 		err := o(req) | 		o(req) | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	return req, nil |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // handleResponse try to parse body to meaningful value | // handleResponse try to parse body to meaningful value | ||||||
| @ -196,69 +131,20 @@ func (c *Client) handleResponse(value interface{}, req *BeegoHTTPRequest) error | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	c.setPointers(resp) | 	c.setPointers(resp) | ||||||
| 
 | 	return req.ResponseForValue(value) | ||||||
| 	if value == nil { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// handle basic type |  | ||||||
| 	switch v := value.(type) { |  | ||||||
| 	case **string: |  | ||||||
| 		s, err := req.String() |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil |  | ||||||
| 		} |  | ||||||
| 		*v = &s |  | ||||||
| 		return nil |  | ||||||
| 	case **[]byte: |  | ||||||
| 		bs, err := req.Bytes() |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil |  | ||||||
| 		} |  | ||||||
| 		*v = &bs |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// try to parse it as content type |  | ||||||
| 	switch strings.Split(resp.Header.Get("Content-Type"), ";")[0] { |  | ||||||
| 	case "application/json": |  | ||||||
| 		return req.ToJSON(value) |  | ||||||
| 	case "text/xml", "application/xml": |  | ||||||
| 		return req.ToXML(value) |  | ||||||
| 	case "text/yaml", "application/x-yaml": |  | ||||||
| 		return req.ToYAML(value) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// try to parse it anyway |  | ||||||
| 	if err := req.ToJSON(value); err == nil { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 	if err := req.ToYAML(value); err == nil { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 	if err := req.ToXML(value); err == nil { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// TODO add new error type about can't parse body |  | ||||||
| 	return berror.Error(UnsupportedBodyType, "unsupported body data") |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Get Send a GET request and try to give its result value | // Get Send a GET request and try to give its result value | ||||||
| func (c *Client) Get(value interface{}, path string, opts ...BeegoHttpRequestOption) error { | func (c *Client) Get(value interface{}, path string, opts ...BeegoHttpRequestOption) error { | ||||||
| 	req, err := c.newRequest(http.MethodGet, path, opts) | 	req := Get(c.Endpoint + path) | ||||||
| 	if err != nil { | 	c.customReq(req, opts) | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	return c.handleResponse(value, req) | 	return c.handleResponse(value, req) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Post Send a POST request and try to give its result value | // Post Send a POST request and try to give its result value | ||||||
| func (c *Client) Post(value interface{}, path string, body interface{}, opts ...BeegoHttpRequestOption) error { | func (c *Client) Post(value interface{}, path string, body interface{}, opts ...BeegoHttpRequestOption) error { | ||||||
| 	req, err := c.newRequest(http.MethodPost, path, opts) | 	req := Post(c.Endpoint + path) | ||||||
| 	if err != nil { | 	c.customReq(req, opts) | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	if body != nil { | 	if body != nil { | ||||||
| 		req = req.Body(body) | 		req = req.Body(body) | ||||||
| 	} | 	} | ||||||
| @ -267,10 +153,8 @@ func (c *Client) Post(value interface{}, path string, body interface{}, opts ... | |||||||
| 
 | 
 | ||||||
| // Put Send a Put request and try to give its result value | // Put Send a Put request and try to give its result value | ||||||
| func (c *Client) Put(value interface{}, path string, body interface{}, opts ...BeegoHttpRequestOption) error { | func (c *Client) Put(value interface{}, path string, body interface{}, opts ...BeegoHttpRequestOption) error { | ||||||
| 	req, err := c.newRequest(http.MethodPut, path, opts) | 	req := Put(c.Endpoint + path) | ||||||
| 	if err != nil { | 	c.customReq(req, opts) | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	if body != nil { | 	if body != nil { | ||||||
| 		req = req.Body(body) | 		req = req.Body(body) | ||||||
| 	} | 	} | ||||||
| @ -279,18 +163,14 @@ func (c *Client) Put(value interface{}, path string, body interface{}, opts ...B | |||||||
| 
 | 
 | ||||||
| // Delete Send a Delete request and try to give its result value | // Delete Send a Delete request and try to give its result value | ||||||
| func (c *Client) Delete(value interface{}, path string, opts ...BeegoHttpRequestOption) error { | func (c *Client) Delete(value interface{}, path string, opts ...BeegoHttpRequestOption) error { | ||||||
| 	req, err := c.newRequest(http.MethodDelete, path, opts) | 	req := Delete(c.Endpoint + path) | ||||||
| 	if err != nil { | 	c.customReq(req, opts) | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	return c.handleResponse(value, req) | 	return c.handleResponse(value, req) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Head Send a Head request and try to give its result value | // Head Send a Head request and try to give its result value | ||||||
| func (c *Client) Head(value interface{}, path string, opts ...BeegoHttpRequestOption) error { | func (c *Client) Head(value interface{}, path string, opts ...BeegoHttpRequestOption) error { | ||||||
| 	req, err := c.newRequest(http.MethodHead, path, opts) | 	req := Head(c.Endpoint + path) | ||||||
| 	if err != nil { | 	c.customReq(req, opts) | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	return c.handleResponse(value, req) | 	return c.handleResponse(value, req) | ||||||
| } | } | ||||||
|  | |||||||
| @ -56,6 +56,7 @@ import ( | |||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const contentTypeKey = "Content-Type" | const contentTypeKey = "Content-Type" | ||||||
|  | 
 | ||||||
| // it will be the last filter and execute request.Do | // it will be the last filter and execute request.Do | ||||||
| var doRequestFilter = func(ctx context.Context, req *BeegoHTTPRequest) (*http.Response, error) { | var doRequestFilter = func(ctx context.Context, req *BeegoHTTPRequest) (*http.Response, error) { | ||||||
| 	return req.doRequest(ctx) | 	return req.doRequest(ctx) | ||||||
| @ -660,6 +661,64 @@ func (b *BeegoHTTPRequest) Response() (*http.Response, error) { | |||||||
| 	return b.getResponse() | 	return b.getResponse() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // ResponseForValue attempts to resolve the response body to value using an existing method. | ||||||
|  | // Calls Response inner. | ||||||
|  | // If value type is **string or **[]byte, the func directly passes response body into the pointer. | ||||||
|  | // Else if response header contain Content-Type, func will call ToJSON\ToXML\ToYAML. | ||||||
|  | // Finally it will try to parse body as json\yaml\xml, If all attempts fail, an error will be returned | ||||||
|  | func (b *BeegoHTTPRequest) ResponseForValue(value interface{}) error { | ||||||
|  | 	if value == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	// handle basic type | ||||||
|  | 	switch v := value.(type) { | ||||||
|  | 	case **string: | ||||||
|  | 		s, err := b.String() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  | 		*v = &s | ||||||
|  | 		return nil | ||||||
|  | 	case **[]byte: | ||||||
|  | 		bs, err := b.Bytes() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  | 		*v = &bs | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	resp, err := b.Response() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	contentType := strings.Split(resp.Header.Get(contentTypeKey), ";")[0] | ||||||
|  | 
 | ||||||
|  | 	// try to parse it as content type | ||||||
|  | 	switch contentType { | ||||||
|  | 	case "application/json": | ||||||
|  | 		return b.ToJSON(value) | ||||||
|  | 	case "text/xml", "application/xml": | ||||||
|  | 		return b.ToXML(value) | ||||||
|  | 	case "text/yaml", "application/x-yaml", "application/x+yaml": | ||||||
|  | 		return b.ToYAML(value) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// try to parse it anyway | ||||||
|  | 	if err := b.ToJSON(value); err == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	if err := b.ToYAML(value); err == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	if err := b.ToXML(value); err == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// TODO add new error type about can't parse body | ||||||
|  | 	return berror.Error(UnsupportedBodyType, "unsupported body data") | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // TimeoutDialer returns functions of connection dialer with timeout settings for http.Transport Dial field. | // TimeoutDialer returns functions of connection dialer with timeout settings for http.Transport Dial field. | ||||||
| // Deprecated | // Deprecated | ||||||
| // we will move this at the end of 2021 | // we will move this at the end of 2021 | ||||||
|  | |||||||
| @ -433,3 +433,7 @@ func TestBeegoHTTPRequest_XMLBody(t *testing.T) { | |||||||
| 	assert.Nil(t, err) | 	assert.Nil(t, err) | ||||||
| 	assert.NotNil(t, req.req.GetBody) | 	assert.NotNil(t, req.req.GetBody) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // TODO | ||||||
|  | func TestBeegoHTTPRequest_ResponseForValue(t *testing.T) { | ||||||
|  | } | ||||||
|  | |||||||
| @ -55,7 +55,7 @@ func SetDefaultSetting(setting BeegoHTTPSettings) { | |||||||
| 	defaultSetting = setting | 	defaultSetting = setting | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // SetDefaultSetting return current default setting | // GetDefaultSetting return current default setting | ||||||
| func GetDefaultSetting() BeegoHTTPSettings { | func GetDefaultSetting() BeegoHTTPSettings { | ||||||
| 	return defaultSetting | 	return defaultSetting | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user