Private/Invoke-SatApi.ps1
|
function Invoke-SatApi { <# .SYNOPSIS Invokes the srrDB API. .DESCRIPTION Internal function that sends HTTP requests to the srrDB API and returns the response. Handles JSON parsing, error handling, and automatic retries with exponential backoff for transient failures. .PARAMETER Uri The complete URI to call .PARAMETER Method The HTTP method to use (default: Get) .PARAMETER Headers Optional headers to include in the request (default: Accept = application/json) .PARAMETER MaxRetries Maximum number of retry attempts for transient failures (default: 3) .PARAMETER RetryDelaySeconds Initial delay in seconds before first retry. Doubles with each subsequent retry (default: 1.0) .PARAMETER RetryableStatusCodes HTTP status codes that should trigger a retry (default: 429, 500, 502, 503, 504) .OUTPUTS PSCustomObject Returns the parsed JSON response from the srrDB API #> [CmdletBinding()] [OutputType([PSCustomObject])] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string] $Uri, [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string] $Method = 'Get', [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [hashtable] $Headers = @{ Accept = 'application/json' }, [Parameter(Mandatory = $false)] [ValidateRange(0, 10)] [int] $MaxRetries = 3, [Parameter(Mandatory = $false)] [ValidateRange(0.1, 60)] [double] $RetryDelaySeconds = 1.0, [Parameter(Mandatory = $false)] [int[]] $RetryableStatusCodes = @(429, 500, 502, 503, 504) ) $apiQueryParameters = @{ Method = $Method Uri = $Uri Headers = $Headers ErrorAction = 'Stop' } Write-Debug 'Invoking srrDB API with the following parameters:' $apiQueryParameters | Out-String | Write-Debug $attempt = 0 $currentDelay = $RetryDelaySeconds $lastException = $null while ($attempt -le $MaxRetries) { try { $response = Invoke-RestMethod @apiQueryParameters # Handle case where response is returned as JSON string (object or array) if ($response -is [string]) { $trimmed = $response.TrimStart() if ($trimmed.StartsWith('{') -or $trimmed.StartsWith('[')) { Write-Debug "Response is JSON string, parsing..." # Use -Depth only if available (PowerShell 6.0+) if ($PSVersionTable.PSVersion.Major -ge 6) { $response = $response | ConvertFrom-Json -Depth 100 } else { $response = $response | ConvertFrom-Json } } } return $response } catch { $lastException = $_ $shouldRetry = $false $statusCode = $null # Extract HTTP status code from exception if ($_.Exception.Response) { $statusCode = [int]$_.Exception.Response.StatusCode $shouldRetry = $statusCode -in $RetryableStatusCodes } elseif ($_.Exception -is [System.Net.WebException]) { $webResponse = $_.Exception.Response -as [System.Net.HttpWebResponse] if ($webResponse) { $statusCode = [int]$webResponse.StatusCode $shouldRetry = $statusCode -in $RetryableStatusCodes } else { # Connection error (no response) - retry $shouldRetry = $true } } elseif ($_.Exception.Message -match 'timeout|timed out') { # Timeout - retry $shouldRetry = $true } if ($shouldRetry -and $attempt -lt $MaxRetries) { $attempt++ $statusInfo = if ($statusCode) { " (HTTP $statusCode)" } else { "" } Write-Verbose "Request failed$statusInfo. Retrying in $currentDelay seconds... (Attempt $attempt of $MaxRetries)" Start-Sleep -Seconds $currentDelay $currentDelay = $currentDelay * 2 # Exponential backoff } else { # Non-retryable error or max retries exceeded if ($attempt -ge $MaxRetries -and $shouldRetry) { throw "Error invoking srrDB API after $MaxRetries retries: $($lastException.Exception.Message)" } throw "Error invoking srrDB API: $($_.Exception.Message)" } } } } |