From 7c7ef98c033a694be8a29730fcb5fd7e7abf01d1 Mon Sep 17 00:00:00 2001 From: Mateusz Filipowicz Date: Wed, 19 Feb 2025 01:03:21 +0100 Subject: [PATCH] feat: rename HttpCustomizer to HttpTransportCustomizer and make it return http.Transport that is later used (#30) * feat: rename HttpCustomizer to HttpTransportCustomizer and make it return http.Transport that is later used * linting --- .editorconfig | 3 +++ README.md | 6 +++--- docs/advanced_topics.md | 23 ----------------------- docs/configuration.md | 13 +++++++------ unifi/client.go | 34 +++++++++++++++++----------------- unifi/unifi_test.go | 18 +++++++++--------- 6 files changed, 39 insertions(+), 58 deletions(-) diff --git a/.editorconfig b/.editorconfig index 156bec3..77d09cc 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,6 +15,9 @@ ij_smart_tabs = false ij_wrap_on_typing = false ij_any_block_comment_add_space = true +[*.go] +indent_style = tab + [*.conf] ij_continuation_indent_size = 2 diff --git a/README.md b/README.md index 9dd8ca7..c47ffb4 100644 --- a/README.md +++ b/README.md @@ -84,14 +84,14 @@ List of available client configuration options is available [here](https://pkg.g ### Customizing HTTP Client -You can customize underlying HTTP client by using `HttpCustomizer` interface: +You can customize underlying HTTP client by using `HttpTransportCustomizer` interface: ```go c, err := unifi.NewClient(&unifi.ClientConfig{ ... - HttpCustomizer: func(transport *http.Transport) error { + HttpTransportCustomizer: func(transport *http.Transport) (*http.Transport, error) { transport.MaxIdleConns = 10 - return nil + return transport, nil }, }) ``` diff --git a/docs/advanced_topics.md b/docs/advanced_topics.md index 0338cb2..bfcf490 100644 --- a/docs/advanced_topics.md +++ b/docs/advanced_topics.md @@ -57,29 +57,6 @@ if err != nil { These helper methods abstract away the boilerplate of manually constructing HTTP requests and processing responses, allowing you to focus on your application's logic while leveraging built-in validation and error handling provided by the SDK. -## Customizing the HTTP Client - -While the basic configuration allows simple modifications, you can fully customize the underlying HTTP client for more -control over connection settings, proxy configuration, TLS settings, and connection pooling. - -Example: - -```go -c, err := unifi.NewClient(&unifi.ClientConfig{ - BaseURL: "https://unifi.localdomain", - APIKey: "your-api-key", - HttpCustomizer: func (transport *http.Transport) error { - transport.MaxIdleConns = 20 - transport.IdleConnTimeout = 90 * time.Second - // Customize TLS settings or add a proxy configuration - return nil - }, -}) -if err != nil { - log.Fatalf("Error creating client: %v", err) -} -``` - ## Interceptors and Middleware Interceptors provide hooks into the request/response cycle and can be used for logging, metrics collection, or modifying diff --git a/docs/configuration.md b/docs/configuration.md index 87bb39e..261862f 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -58,16 +58,17 @@ if err != nil { ## Customizing the HTTP Client -You can provide your own HTTP client configuration using the `HttpCustomizer` callback. This is useful if you need to tweak connection settings like timeouts, idle connection settings, or TLS configurations: +You can provide your own HTTP client configuration using the `HttpTransportCustomizer` callback. This is useful if you need to tweak connection settings like timeouts, idle connection settings, or TLS configurations: ```go c, err := unifi.NewClient(&unifi.ClientConfig{ BaseURL: "https://unifi.localdomain", APIKey: "your-api-key", - HttpCustomizer: func(transport *http.Transport) error { + HttpTransportCustomizer: func(transport *http.Transport) (*http.Transport, error) { transport.MaxIdleConns = 10 // Customize TLS settings, proxy, etc. as needed - return nil + // You can also create new instance of transport and return it, instead of customizing pre-configured + return transport, nil }, }) if err != nil { @@ -132,14 +133,14 @@ import ( ) // customTransportCustomizer customizes the HTTP transport, e.g., setting idle connection limits and TLS options. -func customTransportCustomizer(transport *http.Transport) error { +func customTransportCustomizer(transport *http.Transport) (*http.Transport, error) { transport.MaxIdleConns = 50 transport.IdleConnTimeout = 120 * time.Second // Set a custom TLS configuration transport.TLSClientConfig = &tls.Config{ MinVersion: tls.VersionTLS12, } - return nil + return transport, nil } // myErrorHandler implements a custom error handler for HTTP responses. @@ -175,7 +176,7 @@ func main() { Timeout: 30 * time.Second, // Maximum duration to wait for a response VerifySSL: true, // Enable SSL certificate verification Interceptors: []unifi.ClientInterceptor{&customInterceptor{}}, // Custom interceptors for request/response manipulation - HttpCustomizer: customTransportCustomizer, // Function to customize the underlying HTTP transport + HttpTransportCustomizer: customTransportCustomizer, // Function to customize the underlying HTTP transport UserAgent: "MyCustomAgent/1.0", // Custom User-Agent string ErrorHandler: &myErrorHandler{}, // Custom error handler for processing HTTP response errors UseLocking: true, // Enable internal locking for safe concurrent request processing diff --git a/unifi/client.go b/unifi/client.go index 7014048..45b94e3 100644 --- a/unifi/client.go +++ b/unifi/client.go @@ -30,9 +30,9 @@ const ( DefaultValidation validationMode = SoftValidation // TODO: change to hard in next major version ) -// HttpCustomizer is a function type for customizing the HTTP transport. +// HttpTransportCustomizer is a function type for customizing the HTTP transport. // It receives a pointer to an http.Transport and returns an error if customization fails. -type HttpCustomizer func(transport *http.Transport) error +type HttpTransportCustomizer func(transport *http.Transport) (*http.Transport, error) // ResponseErrorHandler defines a method for handling HTTP response errors. // HandleError processes the HTTP response and returns an error if the response indicates failure. @@ -53,25 +53,25 @@ Fields: Timeout: The maximum duration to wait for responses; default is no timeout. VerifySSL: When false, disables SSL certificate verification. Interceptors: A slice of ClientInterceptor implementations that can modify requests and responses. - HttpCustomizer:An optional function to customize the HTTP transport (e.g., for custom TLS settings). + HttpTransportCustomizer:An optional function to customize the HTTP transport (e.g., for custom TLS settings). UserAgent: The User-Agent header string for outgoing HTTP requests. ErrorHandler: A custom handler for processing HTTP response errors. UseLocking: If true, enables internal locking for concurrent request processing. ValidationMode:The mode for validating request bodies. Can be "soft", "hard", or "disable". */ type ClientConfig struct { - URL string `validate:"required,http_url"` - APIKey string `validate:"required_without_all=User Password"` - User string `validate:"excluded_with=APIKey,required_with=Password"` - Password string `validate:"excluded_with=APIKey,required_with=User"` - Timeout time.Duration // How long to wait for replies, default: forever. - VerifySSL bool - Interceptors []ClientInterceptor - HttpCustomizer HttpCustomizer - UserAgent string - ErrorHandler ResponseErrorHandler - UseLocking bool - ValidationMode validationMode `validate:"omitempty,oneof=soft hard disable"` + URL string `validate:"required,http_url"` + APIKey string `validate:"required_without_all=User Password"` + User string `validate:"excluded_with=APIKey,required_with=Password"` + Password string `validate:"excluded_with=APIKey,required_with=User"` + Timeout time.Duration // How long to wait for replies, default: forever. + VerifySSL bool + Interceptors []ClientInterceptor + HttpTransportCustomizer HttpTransportCustomizer + UserAgent string + ErrorHandler ResponseErrorHandler + UseLocking bool + ValidationMode validationMode `validate:"omitempty,oneof=soft hard disable"` } // Credentials abstracts authentication credentials. @@ -158,8 +158,8 @@ func newClientFromConfig(config *ClientConfig, v *validator) (*client, error) { Proxy: http.ProxyFromEnvironment, TLSClientConfig: &tls.Config{InsecureSkipVerify: !config.VerifySSL}, } - if config.HttpCustomizer != nil { - if err = config.HttpCustomizer(transport); err != nil { + if config.HttpTransportCustomizer != nil { + if transport, err = config.HttpTransportCustomizer(transport); err != nil { return nil, fmt.Errorf("failed customizing HTTP transport: %w", err) } } diff --git a/unifi/unifi_test.go b/unifi/unifi_test.go index d8cf83d..e70a106 100644 --- a/unifi/unifi_test.go +++ b/unifi/unifi_test.go @@ -90,9 +90,9 @@ func TestCustomizeHttpClient(t *testing.T) { _, err := NewClient(&ClientConfig{ URL: localUrl, APIKey: "test-key", - HttpCustomizer: func(transport *http.Transport) error { + HttpTransportCustomizer: func(transport *http.Transport) (*http.Transport, error) { called = true - return nil + return transport, nil }, }) @@ -850,16 +850,16 @@ func TestLoginWithAPIKeyDirect(t *testing.T) { assert.NoError(t, err) } -func TestHttpCustomizerError(t *testing.T) { +func TestHttpTransportCustomizerError(t *testing.T) { t.Parallel() - customizer := func(transport *http.Transport) error { - return errors.New("customization failed") + customizer := func(transport *http.Transport) (*http.Transport, error) { + return nil, errors.New("customization failed") } _, err := NewClient(&ClientConfig{ - URL: testUrl, - APIKey: "test-key", - VerifySSL: false, - HttpCustomizer: customizer, + URL: testUrl, + APIKey: "test-key", + VerifySSL: false, + HttpTransportCustomizer: customizer, }) require.Error(t, err) assert.Contains(t, err.Error(), "failed customizing HTTP transport")