Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve initial version of client creation enhancement #813

Merged
merged 3 commits into from
Aug 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ go_library(
"trace.go",
"transport_js.go",
"transport_other.go",
"transport.go",
"transport112.go",
"util.go",
],
importpath = "github.com/go-resty/resty/v2",
Expand Down
121 changes: 34 additions & 87 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@ import (
"compress/gzip"
"crypto/tls"
"crypto/x509"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"io"
"math"
"net/http"
"net/url"
"os"
Expand Down Expand Up @@ -92,14 +89,34 @@ type (
SuccessHook func(*Client, *Response)
)

// ClientTimeoutSetting struct is used to define custom dialer and transport timeout
// values for the Resty client initialization. The default dialer and transport
// timeout values are -
//
// defaultClientTimeout := &ClientTimeoutSetting{
// DialerTimeout: 30 * time.Second,
// DialerKeepAlive: 30 * time.Second,
// TransportIdleConnTimeout: 90 * time.Second,
// TransportTLSHandshakeTimeout: 10 * time.Second,
// TransportExpectContinueTimeout: 1 * time.Second,
// }
//
// Since v3.0.0
type ClientTimeoutSetting struct {
DialerTimeout time.Duration
DialerKeepAlive time.Duration
TransportIdleConnTimeout time.Duration
TransportTLSHandshakeTimeout time.Duration
TransportExpectContinueTimeout time.Duration
}

// Client struct is used to create Resty client with client level settings,
// these settings are applicable to all the request raised from the client.
//
// Resty also provides an options to override most of the client settings
// at request level.
type Client struct {
BaseURL string
HostURL string // Deprecated: use BaseURL instead. To be removed in v3.0.0 release.
QueryParam url.Values
FormData url.Values
PathParams map[string]string
Expand Down Expand Up @@ -164,21 +181,6 @@ type User struct {
// Client methods
//___________________________________

// SetHostURL method is to set Host URL in the client instance. It will be used with request
// raised from this client with relative URL
//
// // Setting HTTP address
// client.SetHostURL("http://myjeeva.com")
//
// // Setting HTTPS address
// client.SetHostURL("https://myjeeva.com")
//
// Deprecated: use SetBaseURL instead. To be removed in v3.0.0 release.
func (c *Client) SetHostURL(url string) *Client {
c.SetBaseURL(url)
return c
}

// SetBaseURL method is to set Base URL in the client instance. It will be used with request
// raised from this client with relative URL
//
Expand All @@ -191,7 +193,6 @@ func (c *Client) SetHostURL(url string) *Client {
// Since v2.7.0
func (c *Client) SetBaseURL(url string) *Client {
c.BaseURL = strings.TrimRight(url, "/")
c.HostURL = c.BaseURL
return c
}

Expand Down Expand Up @@ -1121,10 +1122,23 @@ func (c *Client) IsProxySet() bool {
}

// GetClient method returns the current `http.Client` used by the resty client.
//
// Since v1.1.0
func (c *Client) GetClient() *http.Client {
return c.httpClient
}

// Transport method returns `*http.Transport` currently in use or error
// in case currently used `transport` is not a `*http.Transport`.
//
// Since v2.8.0 become exported method.
func (c *Client) Transport() (*http.Transport, error) {
if transport, ok := c.httpClient.Transport.(*http.Transport); ok {
return transport, nil
}
return nil, errors.New("current transport is not an *http.Transport instance")
}

// Clone returns a clone of the original client.
//
// Be careful when using this function:
Expand Down Expand Up @@ -1263,17 +1277,6 @@ func (c *Client) tlsConfig() (*tls.Config, error) {
return transport.TLSClientConfig, nil
}

// Transport method returns `*http.Transport` currently in use or error
// in case currently used `transport` is not a `*http.Transport`.
//
// Since v2.8.0 become exported method.
func (c *Client) Transport() (*http.Transport, error) {
if transport, ok := c.httpClient.Transport.(*http.Transport); ok {
return transport, nil
}
return nil, errors.New("current transport is not an *http.Transport instance")
}

// just an internal helper method
func (c *Client) outputLogTo(w io.Writer) *Client {
c.log.(*logger).l.SetOutput(w)
Expand Down Expand Up @@ -1354,59 +1357,3 @@ type MultipartField struct {
ContentType string
io.Reader
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Unexported package methods
//_______________________________________________________________________

func createClient(hc *http.Client) *Client {
if hc.Transport == nil {
hc.Transport = createTransport(nil)
}

c := &Client{ // not setting lang default values
QueryParam: url.Values{},
FormData: url.Values{},
Header: http.Header{},
Cookies: make([]*http.Cookie, 0),
RetryWaitTime: defaultWaitTime,
RetryMaxWaitTime: defaultMaxWaitTime,
PathParams: make(map[string]string),
RawPathParams: make(map[string]string),
JSONMarshal: json.Marshal,
JSONUnmarshal: json.Unmarshal,
XMLMarshal: xml.Marshal,
XMLUnmarshal: xml.Unmarshal,
HeaderAuthorizationKey: http.CanonicalHeaderKey("Authorization"),

jsonEscapeHTML: true,
httpClient: hc,
debugBodySizeLimit: math.MaxInt32,
udBeforeRequestLock: &sync.RWMutex{},
afterResponseLock: &sync.RWMutex{},
}

// Logger
c.SetLogger(createLogger())

// default before request middlewares
c.beforeRequest = []RequestMiddleware{
parseRequestURL,
parseRequestHeader,
parseRequestBody,
createHTTPRequest,
addCredentials,
}

// user defined request middlewares
c.udBeforeRequest = []RequestMiddleware{}

// default after response middlewares
c.afterResponse = []ResponseMiddleware{
responseLogger,
parseResponseBody,
saveResponseIntoFile,
}

return c
}
51 changes: 43 additions & 8 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestClientBasicAuth(t *testing.T) {

c := dc()
c.SetBasicAuth("myuser", "basicauth").
SetHostURL(ts.URL).
SetBaseURL(ts.URL).
SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})

resp, err := c.R().
Expand All @@ -50,7 +50,7 @@ func TestClientAuthToken(t *testing.T) {
c := dc()
c.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF").
SetHostURL(ts.URL + "/")
SetBaseURL(ts.URL + "/")

resp, err := c.R().Get("/profile")

Expand All @@ -66,7 +66,7 @@ func TestClientAuthScheme(t *testing.T) {
// Ensure default Bearer
c.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF").
SetHostURL(ts.URL + "/")
SetBaseURL(ts.URL + "/")

resp, err := c.R().Get("/profile")

Expand Down Expand Up @@ -384,8 +384,8 @@ func TestClientOptions(t *testing.T) {
client.SetContentLength(true)
assertEqual(t, client.setContentLength, true)

client.SetHostURL("http://httpbin.org")
assertEqual(t, "http://httpbin.org", client.HostURL)
client.SetBaseURL("http://httpbin.org")
assertEqual(t, "http://httpbin.org", client.BaseURL)

client.SetHeader(hdrContentTypeKey, "application/json; charset=utf-8")
client.SetHeaders(map[string]string{
Expand Down Expand Up @@ -791,13 +791,48 @@ func TestDebugLogSimultaneously(t *testing.T) {
}
}

func TestNewWithTimeout(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()

customTimeout := &ClientTimeoutSetting{
DialerTimeout: 30 * time.Second,
DialerKeepAlive: 15 * time.Second,
TransportIdleConnTimeout: 120 * time.Second,
TransportTLSHandshakeTimeout: 20 * time.Second,
TransportExpectContinueTimeout: 1 * time.Second,
}
client := NewWithTimeout(customTimeout)
client.SetBaseURL(ts.URL)

resp, err := client.R().Get("/")
assertNil(t, err)
assertEqual(t, resp.String(), "TestGet: text response")
}

func TestNewWithDialer(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()

dialer := &net.Dialer{
Timeout: 15 * time.Second,
KeepAlive: 15 * time.Second,
}
client := NewWithDialer(dialer)
client.SetBaseURL(ts.URL)

resp, err := client.R().Get("/")
assertNil(t, err)
assertEqual(t, resp.String(), "TestGet: text response")
}

func TestNewWithLocalAddr(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()

localAddress, _ := net.ResolveTCPAddr("tcp", "127.0.0.1")
client := NewWithLocalAddr(localAddress)
client.SetHostURL(ts.URL)
client.SetBaseURL(ts.URL)

resp, err := client.R().Get("/")
assertNil(t, err)
Expand Down Expand Up @@ -1012,7 +1047,7 @@ func TestHostURLForGH318AndGH407(t *testing.T) {
// assertNotNil(t, resp)

t.Log("with leading `/` on request & with trailing `/` on host url")
c.SetHostURL(ts.URL + "/")
c.SetBaseURL(ts.URL + "/")
resp, err := c.R().
SetBody(map[string]interface{}{"username": "testuser", "password": "testpass"}).
Post("/login")
Expand Down Expand Up @@ -1060,7 +1095,7 @@ func TestUnixSocket(t *testing.T) {

// Set the previous transport that we created, set the scheme of the communication to the
// socket and set the unixSocket as the HostURL.
client.SetTransport(&transport).SetScheme("http").SetHostURL(unixSocketAddr)
client.SetTransport(&transport).SetScheme("http").SetBaseURL(unixSocketAddr)

// No need to write the host's URL on the request, just the path.
res, err := client.R().Get("http://localhost/")
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/go-resty/resty/v3

go 1.20
go 1.18

require (
golang.org/x/net v0.25.0
Expand Down
7 changes: 1 addition & 6 deletions middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,7 @@ func parseRequestURL(c *Client, r *Request) error {
r.URL = "/" + r.URL
}

// TODO: change to use c.BaseURL only in v3.0.0
baseURL := c.BaseURL
if len(baseURL) == 0 {
baseURL = c.HostURL
}
reqURL, err = url.Parse(baseURL + r.URL)
reqURL, err = url.Parse(c.BaseURL + r.URL)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion middleware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ func Test_parseRequestURL(t *testing.T) {
{
name: "using deprecated HostURL with relative path in request URL",
init: func(c *Client, r *Request) {
c.HostURL = "https://example.com"
c.BaseURL = "https://example.com"
r.URL = "foo/bar"
},
expectedURL: "https://example.com/foo/bar",
Expand Down
Loading