diff --git a/README.md b/README.md index accfff3..41411b6 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,40 @@ This HTTP client is intended to be used with targetted SDK's and terraform provi TBC +## Getting Started +' +{ + "Integration": { + "FQDN": "https://api.example.com", + "AuthMethodDescriptor": "Bearer" + // other necessary fields for integration + }, + "HideSensitiveData": true, + "CustomCookies": [ + { + "Name": "sessionid", + "Value": "abc123", + "Path": "/", + "Domain": "example.com", + "Expires": "2025-01-02T15:04:05Z", + "MaxAge": 86400, + "Secure": true, + "HttpOnly": true, + "SameSite": 1 + } + ], + "MaxRetryAttempts": 5, + "MaxConcurrentRequests": 10, + "EnableDynamicRateLimiting": true, + "CustomTimeout": "10s", + "TokenRefreshBufferPeriod": "2m", + "TotalRetryDuration": "10m", + "FollowRedirects": true, + "MaxRedirects": 3, + "ConcurrencyManagementEnabled": true +} +' + ## Reporting Issues and Feedback @@ -53,13 +87,4 @@ If you would like to become an active contributor to this repository or project, [GitHubDocs]: [AzureDevOpsDocs]: [GitHubIssues]: -[Contributing]: CONTRIBUTING.md - - -[Az]: -[AzGallery]: -[PowerShellCore]: - - -[MicrosoftAzureDocs]: -[PowerShellDocs]: +[Contributing]: CONTRIBUTING.md \ No newline at end of file diff --git a/httpclient/config_validation.go b/httpclient/config_validation.go index 4b879b2..200cdca 100644 --- a/httpclient/config_validation.go +++ b/httpclient/config_validation.go @@ -3,7 +3,11 @@ package httpclient import ( + "encoding/json" "errors" + "fmt" + "io" + "os" "time" ) @@ -24,16 +28,51 @@ const ( DefaultMaxRedirects = 5 ) -// TODO migrate all the loose strings - -// TODO LoadConfigFromFile Func +// LoadConfigFromFile loads http client configuration settings from a JSON file. func LoadConfigFromFile(filepath string) (*ClientConfig, error) { - return nil, nil + absPath, err := validateFilePath(filepath) + if err != nil { + return nil, fmt.Errorf("invalid file path: %v", err) + } + + file, err := os.Open(absPath) + if err != nil { + return nil, fmt.Errorf("could not open file: %v", err) + } + defer file.Close() + + byteValue, err := io.ReadAll(file) + if err != nil { + return nil, fmt.Errorf("could not read file: %v", err) + } + + var config ClientConfig + err = json.Unmarshal(byteValue, &config) + if err != nil { + return nil, fmt.Errorf("could not unmarshal JSON: %v", err) + } + + // Set default values for missing fields. + SetDefaultValuesClientConfig(&config) + + return &config, nil } -// TODO LoadConfigFromEnv Func +// LoadConfigFromEnv loads configuration settings from environment variables. func LoadConfigFromEnv() (*ClientConfig, error) { - return nil, nil + config := &ClientConfig{ + HideSensitiveData: getEnvAsBool("HIDE_SENSITIVE_DATA", DefaultHideSensitiveData), + MaxRetryAttempts: getEnvAsInt("MAX_RETRY_ATTEMPTS", DefaultMaxRetryAttempts), + MaxConcurrentRequests: getEnvAsInt("MAX_CONCURRENT_REQUESTS", DefaultMaxConcurrentRequests), + EnableDynamicRateLimiting: getEnvAsBool("ENABLE_DYNAMIC_RATE_LIMITING", DefaultEnableDynamicRateLimiting), + CustomTimeout: getEnvAsDuration("CUSTOM_TIMEOUT", DefaultCustomTimeout), + TokenRefreshBufferPeriod: getEnvAsDuration("TOKEN_REFRESH_BUFFER_PERIOD", DefaultTokenRefreshBufferPeriod), + TotalRetryDuration: getEnvAsDuration("TOTAL_RETRY_DURATION", DefaultTotalRetryDuration), + FollowRedirects: getEnvAsBool("FOLLOW_REDIRECTS", DefaultFollowRedirects), + MaxRedirects: getEnvAsInt("MAX_REDIRECTS", DefaultMaxRedirects), + } + + return config, nil } // TODO Review validateClientConfig diff --git a/httpclient/integration.go b/httpclient/integration.go index 83cd628..923783f 100644 --- a/httpclient/integration.go +++ b/httpclient/integration.go @@ -1,11 +1,12 @@ -// apiintegrations/apihandler/apihandler.go +// httpclient/integration.go package httpclient import ( "net/http" ) -// TODO comment +// APIIntegration is an interface that defines the methods required for an API integration. These are obtained from go-api-http-client-integrations. +// The methods defined in this interface are used by the HTTP client to authenticate and prepare requests for the API. type APIIntegration interface { GetFQDN() string ConstructURL(endpoint string) string diff --git a/httpclient/utility.go b/httpclient/utility.go index 9abf70f..4a2f619 100644 --- a/httpclient/utility.go +++ b/httpclient/utility.go @@ -1,11 +1,15 @@ +// httpclient/utility.go package httpclient import ( "errors" "fmt" + "os" "path/filepath" "regexp" + "strconv" "strings" + "time" ) // TODO all func comments in here @@ -74,3 +78,44 @@ func validatePassword(password string) error { } return nil } + +// getEnvAsString reads an environment variable as a string, with a fallback default value. +func getEnvAsString(name string, defaultVal string) string { + if value, exists := os.LookupEnv(name); exists { + return value + } + return defaultVal +} + +// getEnvAsBool reads an environment variable as a boolean, with a fallback default value. +func getEnvAsBool(name string, defaultVal bool) bool { + if value, exists := os.LookupEnv(name); exists { + boolValue, err := strconv.ParseBool(value) + if err == nil { + return boolValue + } + } + return defaultVal +} + +// getEnvAsInt reads an environment variable as an integer, with a fallback default value. +func getEnvAsInt(name string, defaultVal int) int { + if value, exists := os.LookupEnv(name); exists { + intValue, err := strconv.Atoi(value) + if err == nil { + return intValue + } + } + return defaultVal +} + +// getEnvAsDuration reads an environment variable as a duration, with a fallback default value. +func getEnvAsDuration(name string, defaultVal time.Duration) time.Duration { + if value, exists := os.LookupEnv(name); exists { + durationValue, err := time.ParseDuration(value) + if err == nil { + return durationValue + } + } + return defaultVal +}