Documentation
¶
Overview ¶
Package httpclient provides a configurable HTTP client module for the modular framework.
Package httpclient provides a configurable HTTP client module for the modular framework.
Package httpclient provides a configurable HTTP client module for the modular framework.
This module offers a production-ready HTTP client with comprehensive configuration options, request/response logging, connection pooling, timeout management, and request modification capabilities. It's designed for reliable HTTP communication in microservices and web applications.
Features ¶
The httpclient module provides the following capabilities:
- Configurable connection pooling and keep-alive settings
- Request and response timeout management
- TLS handshake timeout configuration
- Comprehensive request/response logging with file output
- Request modification pipeline for adding headers, authentication, etc.
- Performance-optimized transport settings
- Support for compression and keep-alive control
- Service interface for dependency injection
Configuration ¶
The module can be configured through the Config structure:
config := &Config{ MaxIdleConns: 100, // total idle connections MaxIdleConnsPerHost: 10, // idle connections per host IdleConnTimeout: 90, // idle connection timeout (seconds) RequestTimeout: 30, // request timeout (seconds) TLSTimeout: 10, // TLS handshake timeout (seconds) DisableCompression: false, // enable gzip compression DisableKeepAlives: false, // enable connection reuse Verbose: true, // enable request/response logging VerboseOptions: &VerboseOptions{ LogToFile: true, LogFilePath: "/var/log/httpclient", }, }
Service Registration ¶
The module registers itself as a service for dependency injection:
// Get the HTTP client service client := app.GetService("httpclient").(httpclient.ClientService) // Use the client resp, err := client.Client().Get("https://api.example.com/users") // Create a client with custom timeout timeoutClient := client.WithTimeout(60) resp, err := timeoutClient.Post("https://api.example.com/upload", "application/json", data)
Usage Examples ¶
Basic HTTP requests:
// GET request resp, err := client.Client().Get("https://api.example.com/health") if err != nil { return err } defer resp.Body.Close() // POST request with JSON jsonData := bytes.NewBuffer([]byte(`{"name": "test"}`)) resp, err := client.Client().Post( "https://api.example.com/users", "application/json", jsonData, )
Request modification for authentication:
// Set up request modifier for API key authentication modifier := func(req *http.Request) *http.Request { req.Header.Set("Authorization", "Bearer "+apiToken) req.Header.Set("User-Agent", "MyApp/1.0") return req } client.SetRequestModifier(modifier) // All subsequent requests will include the headers resp, err := client.Client().Get("https://api.example.com/protected")
Custom timeout scenarios:
// Short timeout for health checks healthClient := client.WithTimeout(5) resp, err := healthClient.Get("https://service.example.com/health") // Long timeout for file uploads uploadClient := client.WithTimeout(300) resp, err := uploadClient.Post("https://api.example.com/upload", contentType, fileData)
Logging and Debugging ¶
When verbose logging is enabled, the module logs detailed request and response information including headers, bodies, and timing data. This is invaluable for debugging API integrations and monitoring HTTP performance.
Log output includes:
- Request method, URL, and headers
- Request body (configurable)
- Response status, headers, and body
- Request duration and timing breakdown
- Error details and retry information
Performance Considerations ¶
The module is optimized for production use with:
- Connection pooling to reduce connection overhead
- Keep-alive connections for better performance
- Configurable timeouts to prevent resource leaks
- Optional compression to reduce bandwidth usage
- Efficient request modification pipeline
Index ¶
- Constants
- func NewHTTPClientModule() modular.Module
- type ClientService
- type Config
- type FileLogger
- type HTTPClientModule
- func (m *HTTPClientModule) Client() *http.Client
- func (m *HTTPClientModule) Dependencies() []string
- func (m *HTTPClientModule) Init(app modular.Application) error
- func (m *HTTPClientModule) Name() string
- func (m *HTTPClientModule) ProvidesServices() []modular.ServiceProvider
- func (m *HTTPClientModule) RegisterConfig(app modular.Application) error
- func (m *HTTPClientModule) RequestModifier() RequestModifierFunc
- func (m *HTTPClientModule) RequiresServices() []modular.ServiceDependency
- func (m *HTTPClientModule) SetRequestModifier(modifier RequestModifierFunc)
- func (m *HTTPClientModule) Start(context.Context) error
- func (m *HTTPClientModule) Stop(context.Context) error
- func (m *HTTPClientModule) WithTimeout(timeoutSeconds int) *http.Client
- type RequestModifierFunc
- type VerboseOptions
Constants ¶
const ModuleName = "httpclient"
ModuleName is the unique identifier for the httpclient module.
const ServiceName = "httpclient"
ServiceName is the name of the service provided by this module. Other modules can use this name to request the HTTP client service through dependency injection.
Variables ¶
This section is empty.
Functions ¶
func NewHTTPClientModule ¶
NewHTTPClientModule creates a new instance of the HTTP client module. This is the primary constructor for the httpclient module and should be used when registering the module with the application.
Example:
app.RegisterModule(httpclient.NewHTTPClientModule())
Types ¶
type ClientService ¶
type ClientService interface { // Client returns the configured http.Client instance. // This client uses the module's configuration for timeouts, connection // pooling, compression, and other transport settings. The client is // thread-safe and can be used concurrently. // // The returned client includes any configured request modification // pipeline and verbose logging if enabled. Client() *http.Client // RequestModifier returns a modifier function that can modify a request before it's sent. // This function applies any configured request modifications such as // authentication headers, user agents, or custom headers. // // The modifier can be used manually when creating custom requests: // req, _ := http.NewRequest("POST", url, body) // req = modifier(req) // resp, err := client.Do(req) RequestModifier() RequestModifierFunc // WithTimeout creates a new client with the specified timeout in seconds. // This is useful for creating clients with different timeout requirements // without affecting the default client configuration. // // The new client inherits all other configuration from the module // (connection pooling, compression, etc.) but uses the specified timeout. // // Common timeout scenarios: // - Health checks: 5-10 seconds // - API calls: 30-60 seconds // - File uploads: 300+ seconds WithTimeout(timeoutSeconds int) *http.Client }
ClientService defines the interface for the HTTP client service. This interface provides access to configured HTTP clients and request modification capabilities. Any module that needs to make HTTP requests can use this service through dependency injection.
The service provides multiple ways to access HTTP clients:
- Default client with module configuration
- Timeout-specific clients for different use cases
- Request modification pipeline for common headers/auth
Example usage:
// Basic usage client := httpClientService.Client() resp, err := client.Get("https://api.example.com/data") // Custom timeout shortTimeoutClient := httpClientService.WithTimeout(5) resp, err := shortTimeoutClient.Get("https://api.example.com/health") // Request modification modifier := httpClientService.RequestModifier() req, _ := http.NewRequest("GET", "https://api.example.com/data", nil) modifiedReq := modifier(req)
type Config ¶
type Config struct { // MaxIdleConns controls the maximum number of idle (keep-alive) connections across all hosts. // This setting affects the total connection pool size and memory usage. // Higher values allow more concurrent connections but use more memory. // Default: 100 MaxIdleConns int `yaml:"max_idle_conns" json:"max_idle_conns" env:"MAX_IDLE_CONNS"` // MaxIdleConnsPerHost controls the maximum idle (keep-alive) connections to keep per-host. // This prevents a single host from monopolizing the connection pool. // Should be tuned based on expected traffic patterns to specific hosts. // Default: 10 MaxIdleConnsPerHost int `yaml:"max_idle_conns_per_host" json:"max_idle_conns_per_host" env:"MAX_IDLE_CONNS_PER_HOST"` // IdleConnTimeout is the maximum amount of time an idle connection will remain idle // before closing itself, in seconds. This helps prevent stale connections and // reduces server-side resource usage. // Default: 90 seconds IdleConnTimeout int `yaml:"idle_conn_timeout" json:"idle_conn_timeout" env:"IDLE_CONN_TIMEOUT"` // RequestTimeout is the maximum time for a request to complete, in seconds. // This includes connection time, any redirects, and reading the response body. // Use WithTimeout() method for per-request timeout overrides. // Default: 30 seconds RequestTimeout int `yaml:"request_timeout" json:"request_timeout" env:"REQUEST_TIMEOUT"` // TLSTimeout is the maximum time waiting for TLS handshake, in seconds. // This only affects HTTPS connections and should be set based on expected // network latency and certificate chain complexity. // Default: 10 seconds TLSTimeout int `yaml:"tls_timeout" json:"tls_timeout" env:"TLS_TIMEOUT"` // DisableCompression disables decompressing response bodies. // When false (default), the client automatically handles gzip compression. // Set to true if you need to handle compression manually or want raw responses. // Default: false (compression enabled) DisableCompression bool `yaml:"disable_compression" json:"disable_compression" env:"DISABLE_COMPRESSION"` // DisableKeepAlives disables HTTP keep-alive and will only use connections for a single request. // This can be useful for debugging or when connecting to servers that don't handle // keep-alives properly, but significantly impacts performance. // Default: false (keep-alives enabled) DisableKeepAlives bool `yaml:"disable_keep_alives" json:"disable_keep_alives" env:"DISABLE_KEEP_ALIVES"` // Verbose enables detailed logging of HTTP requests and responses. // When enabled, logs include request/response headers, bodies, timing information, // and error details. Very useful for debugging but can impact performance. // Default: false Verbose bool `yaml:"verbose" json:"verbose" env:"VERBOSE"` // VerboseOptions configures the behavior when Verbose is enabled. // This allows fine-grained control over what gets logged and where. VerboseOptions *VerboseOptions `yaml:"verbose_options" json:"verbose_options" env:"VERBOSE_OPTIONS"` }
Config defines the configuration for the HTTP client module. This structure contains all the settings needed to configure HTTP client behavior, connection pooling, timeouts, and logging.
Configuration can be provided through JSON, YAML, or environment variables. The struct tags define the mapping for each configuration source.
Example YAML configuration:
max_idle_conns: 200 max_idle_conns_per_host: 20 idle_conn_timeout: 120 request_timeout: 60 tls_timeout: 15 disable_compression: false disable_keep_alives: false verbose: true verbose_options: log_headers: true log_body: true max_body_log_size: 1024 log_to_file: true log_file_path: "/var/log/httpclient"
Example environment variables:
HTTPCLIENT_MAX_IDLE_CONNS=200 HTTPCLIENT_REQUEST_TIMEOUT=60 HTTPCLIENT_VERBOSE=true
func (*Config) GetTimeout ¶
GetTimeout converts a timeout value from seconds to time.Duration.
type FileLogger ¶
type FileLogger struct {
// contains filtered or unexported fields
}
FileLogger handles logging HTTP request and response data to files.
func NewFileLogger ¶
func NewFileLogger(baseDir string, logger modular.Logger) (*FileLogger, error)
NewFileLogger creates a new file logger that writes HTTP data to files.
func (*FileLogger) Close ¶
func (f *FileLogger) Close() error
Close closes any open files and cleans up resources.
func (*FileLogger) LogRequest ¶
func (f *FileLogger) LogRequest(id string, data []byte) error
LogRequest writes request data to a file.
func (*FileLogger) LogResponse ¶
func (f *FileLogger) LogResponse(id string, data []byte) error
LogResponse writes response data to a file.
func (*FileLogger) LogTransactionToFile ¶
func (f *FileLogger) LogTransactionToFile(id string, reqData, respData []byte, duration time.Duration, url string) error
LogTransactionToFile logs both request and response data to a single file for easier analysis.
type HTTPClientModule ¶
type HTTPClientModule struct {
// contains filtered or unexported fields
}
HTTPClientModule implements a configurable HTTP client module. It provides a production-ready HTTP client with comprehensive configuration options, logging capabilities, and request modification features.
The module implements the following interfaces:
- modular.Module: Basic module lifecycle
- modular.Configurable: Configuration management
- modular.ServiceAware: Service dependency management
- ClientService: HTTP client service interface
The HTTP client is thread-safe and can be used concurrently from multiple goroutines.
func (*HTTPClientModule) Client ¶
func (m *HTTPClientModule) Client() *http.Client
Client returns the configured http.Client instance.
func (*HTTPClientModule) Dependencies ¶
func (m *HTTPClientModule) Dependencies() []string
Dependencies returns the names of modules this module depends on.
func (*HTTPClientModule) Init ¶
func (m *HTTPClientModule) Init(app modular.Application) error
Init initializes the httpclient module with the application context. This method is called after all modules have been registered and their configurations loaded. It sets up the HTTP client, transport, and logging.
The initialization process:
- Retrieves the module's configuration
- Sets up logging
- Creates and configures the HTTP transport with connection pooling
- Sets up request/response logging if verbose mode is enabled
- Creates the HTTP client with configured transport and middleware
- Initializes request modification pipeline
Transport configuration includes:
- Connection pooling settings for optimal performance
- Timeout configurations for reliability
- Compression and keep-alive settings
- TLS handshake timeout for secure connections
func (*HTTPClientModule) Name ¶
func (m *HTTPClientModule) Name() string
Name returns the unique identifier for this module. This name is used for service registration, dependency resolution, and configuration section identification.
func (*HTTPClientModule) ProvidesServices ¶
func (m *HTTPClientModule) ProvidesServices() []modular.ServiceProvider
ProvidesServices returns services provided by this module.
func (*HTTPClientModule) RegisterConfig ¶
func (m *HTTPClientModule) RegisterConfig(app modular.Application) error
RegisterConfig registers the module's configuration structure. This method is called during application initialization to register the default configuration values for the httpclient module.
Default configuration:
- MaxIdleConns: 100 (total idle connections)
- MaxIdleConnsPerHost: 10 (idle connections per host)
- IdleConnTimeout: 90 seconds
- RequestTimeout: 30 seconds
- TLSTimeout: 10 seconds
- DisableCompression: false (compression enabled)
- DisableKeepAlives: false (keep-alives enabled)
- Verbose: false (logging disabled)
func (*HTTPClientModule) RequestModifier ¶
func (m *HTTPClientModule) RequestModifier() RequestModifierFunc
RequestModifier returns a modifier function that can modify a request before it's sent.
func (*HTTPClientModule) RequiresServices ¶
func (m *HTTPClientModule) RequiresServices() []modular.ServiceDependency
RequiresServices returns services required by this module.
func (*HTTPClientModule) SetRequestModifier ¶
func (m *HTTPClientModule) SetRequestModifier(modifier RequestModifierFunc)
SetRequestModifier sets the request modifier function.
func (*HTTPClientModule) Start ¶
func (m *HTTPClientModule) Start(context.Context) error
Start performs startup logic for the module.
func (*HTTPClientModule) Stop ¶
func (m *HTTPClientModule) Stop(context.Context) error
Stop performs shutdown logic for the module.
func (*HTTPClientModule) WithTimeout ¶
func (m *HTTPClientModule) WithTimeout(timeoutSeconds int) *http.Client
WithTimeout creates a new client with the specified timeout in seconds.
type RequestModifierFunc ¶
RequestModifierFunc is a function type that can be used to modify an HTTP request before it is sent by the client.
Request modifiers are useful for:
- Adding authentication headers (Bearer tokens, API keys)
- Setting common headers (User-Agent, Content-Type)
- Adding request tracking (correlation IDs, request IDs)
- Request logging and debugging
- Request validation and sanitization
Example modifier implementations:
// API key authentication func apiKeyModifier(apiKey string) RequestModifierFunc { return func(req *http.Request) *http.Request { req.Header.Set("Authorization", "Bearer "+apiKey) return req } } // Request tracing func tracingModifier(req *http.Request) *http.Request { req.Header.Set("X-Request-ID", generateRequestID()) req.Header.Set("X-Trace-ID", getTraceID(req.Context())) return req } // User agent setting func userAgentModifier(userAgent string) RequestModifierFunc { return func(req *http.Request) *http.Request { req.Header.Set("User-Agent", userAgent) return req } }
type VerboseOptions ¶
type VerboseOptions struct { // LogHeaders enables logging of request and response headers. // This includes all HTTP headers sent and received, which can contain // sensitive information like authorization tokens. // Default: false LogHeaders bool `yaml:"log_headers" json:"log_headers" env:"LOG_HEADERS"` // LogBody enables logging of request and response bodies. // This can generate large amounts of log data and may contain sensitive // information. Consider using MaxBodyLogSize to limit logged content. // Default: false LogBody bool `yaml:"log_body" json:"log_body" env:"LOG_BODY"` // MaxBodyLogSize limits the size of logged request and response bodies. // Bodies larger than this size will be truncated in logs. Set to 0 for no limit. // Helps prevent log spam from large file uploads or downloads. // Default: 0 (no limit) MaxBodyLogSize int `yaml:"max_body_log_size" json:"max_body_log_size" env:"MAX_BODY_LOG_SIZE"` // LogToFile enables logging to files instead of just the application logger. // When enabled, HTTP logs are written to separate files for easier analysis. // Requires LogFilePath to be set. // Default: false LogToFile bool `yaml:"log_to_file" json:"log_to_file" env:"LOG_TO_FILE"` // LogFilePath is the directory where log files will be written. // Log files are organized by date and include request/response details. // The directory must be writable by the application. // Default: "" (current directory) LogFilePath string `yaml:"log_file_path" json:"log_file_path" env:"LOG_FILE_PATH"` }
VerboseOptions configures the behavior of verbose logging. These options provide fine-grained control over HTTP request/response logging to balance debugging needs with performance and security considerations.