Repository: meilisearch/meilisearch-go

Issue:
Add customization option for HTTP transport
**Description**
Currently, we use an optimized transport as the default for the HTTP client:

[https://github.com/meilisearch/meilisearch-go/blob/108f4168ed876cf22f2e3d70ce8f53d14dd0e8e9/options.go#L139-L152](https://github.com/meilisearch/meilisearch-go/blob/108f4168ed876cf22f2e3d70ce8f53d14dd0e8e9/options.go#L139-L152)

We can now introduce a custom option to allow users to apply their own HTTP transport configuration to the default client.

**Basic Example**

```go
func WithCustomTransport(tr *http.Transport) Option {
	return func(opt *meiliOpt) {
		if tr != nil {
			opt.client.Transport = tr
		}
	}
}
```


Discussion:

Solution patch:
diff --git a/README.md b/README.md
index ebffd3b..4070a4c 100644
--- a/README.md
+++ b/README.md
@@ -31,7 +31,7 @@
 ## Table of Contents
 
 - [📖 Documentation](#-documentation)
-- [🔧 Installation](#-installation)
+- [🔧 Installation](#-installation--120)
 - [🚀 Getting started](#-getting-started)
   - [Add documents](#add-documents)
   - [Basic search](#basic-search)
@@ -51,7 +51,7 @@ This readme contains all the documentation you need to start using this Meilisea
 For general information on how to use Meilisearch—such as our API reference, tutorials, guides, and in-depth articles—refer to our [main documentation website](https://www.meilisearch.com/docs/).
 
 
-## 🔧 Installation
+## 🔧 Installation (>= 1.20)
 
 With `go get` in command line:
 ```bash
diff --git a/options.go b/options.go
index 577805c..4a8daad 100644
--- a/options.go
+++ b/options.go
@@ -1,15 +1,18 @@
 package meilisearch
 
 import (
+	"context"
 	"crypto/tls"
 	"encoding/json"
 	"net"
 	"net/http"
+	"net/url"
 	"time"
 )
 
 type meiliOpt struct {
 	client          *http.Client
+	transport       *http.Transport
 	apiKey          string
 	contentEncoding *encodingOpt
 	retryOnStatus   map[int]bool
@@ -27,10 +30,12 @@ type encodingOpt struct {
 type Option func(*meiliOpt)
 
 func _defaultOpts() *meiliOpt {
+	transport := baseTransport()
 	return &meiliOpt{
 		client: &http.Client{
-			Transport: baseTransport(),
+			Transport: transport,
 		},
+		transport: transport,
 		contentEncoding: &encodingOpt{
 			level: DefaultCompression,
 		},
@@ -53,6 +58,59 @@ func WithCustomClient(client *http.Client) Option {
 	}
 }
 
+// WithCustomProxy sets a custom proxy function
+func WithCustomProxy(proxy func(*http.Request) (*url.URL, error)) Option {
+	return func(opt *meiliOpt) {
+		if proxy != nil {
+			opt.transport.Proxy = proxy
+		}
+	}
+}
+
+// WithCustomDialContext sets a custom dial context
+func WithCustomDialContext(dial func(ctx context.Context, network, addr string) (net.Conn, error)) Option {
+	return func(opt *meiliOpt) {
+		if dial != nil {
+			opt.transport.DialContext = dial
+		}
+	}
+}
+
+// WithCustomMaxIdleConns sets the max number of idle connections
+func WithCustomMaxIdleConns(maxIdleConns int) Option {
+	return func(opt *meiliOpt) {
+		opt.transport.MaxIdleConns = maxIdleConns
+	}
+}
+
+// WithCustomMaxIdleConnsPerHost sets max idle connections per host
+func WithCustomMaxIdleConnsPerHost(maxIdleConnsPerHost int) Option {
+	return func(opt *meiliOpt) {
+		opt.transport.MaxIdleConnsPerHost = maxIdleConnsPerHost
+	}
+}
+
+// WithCustomIdleConnTimeout sets the idle connection timeout
+func WithCustomIdleConnTimeout(timeout time.Duration) Option {
+	return func(opt *meiliOpt) {
+		opt.transport.IdleConnTimeout = timeout
+	}
+}
+
+// WithCustomTLSHandshakeTimeout sets the TLS handshake timeout
+func WithCustomTLSHandshakeTimeout(timeout time.Duration) Option {
+	return func(opt *meiliOpt) {
+		opt.transport.TLSHandshakeTimeout = timeout
+	}
+}
+
+// WithCustomExpectContinueTimeout sets the Expect-Continue timeout
+func WithCustomExpectContinueTimeout(timeout time.Duration) Option {
+	return func(opt *meiliOpt) {
+		opt.transport.ExpectContinueTimeout = timeout
+	}
+}
+
 // WithCustomClientWithTLS client support tls configuration
 func WithCustomClientWithTLS(tlsConfig *tls.Config) Option {
 	return func(opt *meiliOpt) {



Test patch:
diff --git a/options_test.go b/options_test.go
index a03ccf8..5bd0b0a 100644
--- a/options_test.go
+++ b/options_test.go
@@ -1,13 +1,102 @@
 package meilisearch
 
 import (
+	"context"
 	"crypto/tls"
 	"encoding/json"
-	"github.com/stretchr/testify/require"
+	"net"
 	"net/http"
+	"net/url"
+	"reflect"
 	"testing"
+	"time"
+
+	"github.com/stretchr/testify/require"
 )
 
+func TestOptions_WithCustomProxy(t *testing.T) {
+	proxy := func(*http.Request) (*url.URL, error) { return nil, nil }
+	meili := New("localhost:7700", WithCustomProxy(proxy))
+	require.NotNil(t, meili)
+
+	m, ok := meili.(*meilisearch)
+	require.True(t, ok)
+	transport, ok := m.client.client.Transport.(*http.Transport)
+	require.True(t, ok)
+
+	require.Equal(t, reflect.ValueOf(proxy).Pointer(), reflect.ValueOf(transport.Proxy).Pointer())
+}
+
+func TestOptions_WithCustomDialContext(t *testing.T) {
+	dial := func(ctx context.Context, network, addr string) (net.Conn, error) { return nil, nil }
+	meili := New("localhost:7700", WithCustomDialContext(dial))
+	require.NotNil(t, meili)
+
+	m, ok := meili.(*meilisearch)
+	require.True(t, ok)
+	transport, ok := m.client.client.Transport.(*http.Transport)
+	require.True(t, ok)
+	require.Equal(t, reflect.ValueOf(dial).Pointer(), reflect.ValueOf(transport.DialContext).Pointer())
+}
+
+func TestOptions_WithCustomMaxIdleConns(t *testing.T) {
+	meili := New("localhost:7700", WithCustomMaxIdleConns(50))
+	require.NotNil(t, meili)
+
+	m, ok := meili.(*meilisearch)
+	require.True(t, ok)
+	transport, ok := m.client.client.Transport.(*http.Transport)
+	require.True(t, ok)
+	require.Equal(t, 50, transport.MaxIdleConns)
+}
+
+func TestOptions_WithCustomMaxIdleConnsPerHost(t *testing.T) {
+	meili := New("localhost:7700", WithCustomMaxIdleConnsPerHost(50))
+	require.NotNil(t, meili)
+
+	m, ok := meili.(*meilisearch)
+	require.True(t, ok)
+	transport, ok := m.client.client.Transport.(*http.Transport)
+	require.True(t, ok)
+	require.Equal(t, 50, transport.MaxIdleConnsPerHost)
+}
+
+func TestOptions_WithCustomIdleConnTimeout(t *testing.T) {
+	timeout := time.Second * 5
+	meili := New("localhost:7700", WithCustomIdleConnTimeout(timeout))
+	require.NotNil(t, meili)
+
+	m, ok := meili.(*meilisearch)
+	require.True(t, ok)
+	transport, ok := m.client.client.Transport.(*http.Transport)
+	require.True(t, ok)
+	require.Equal(t, timeout, transport.IdleConnTimeout)
+}
+
+func TestOptions_WithCustomTLSHandshakeTimeout(t *testing.T) {
+	timeout := time.Second * 5
+	meili := New("localhost:7700", WithCustomTLSHandshakeTimeout(timeout))
+	require.NotNil(t, meili)
+
+	m, ok := meili.(*meilisearch)
+	require.True(t, ok)
+	transport, ok := m.client.client.Transport.(*http.Transport)
+	require.True(t, ok)
+	require.Equal(t, timeout, transport.TLSHandshakeTimeout)
+}
+
+func TestOptions_WithCustomExpectContinueTimeout(t *testing.T) {
+	timeout := time.Second * 5
+	meili := New("localhost:7700", WithCustomExpectContinueTimeout(timeout))
+	require.NotNil(t, meili)
+
+	m, ok := meili.(*meilisearch)
+	require.True(t, ok)
+	transport, ok := m.client.client.Transport.(*http.Transport)
+	require.True(t, ok)
+	require.Equal(t, timeout, transport.ExpectContinueTimeout)
+}
+
 func TestOptions_WithCustomClient(t *testing.T) {
 	meili := New("localhost:7700", WithCustomClient(http.DefaultClient))
 	require.NotNil(t, meili)