Private/Invoke-VergeAPI.ps1
|
function Invoke-VergeAPI { <# .SYNOPSIS Internal function to make HTTP requests to the VergeOS API. .DESCRIPTION Invoke-VergeAPI is the core HTTP client for all VergeOS API operations. It handles authentication, TLS configuration, error handling, and pagination. .PARAMETER Method The HTTP method (GET, POST, PUT, DELETE, PATCH). .PARAMETER Endpoint The API endpoint path (e.g., 'vms', 'vnets/123'). .PARAMETER Body The request body for POST/PUT/PATCH requests. .PARAMETER Query Query string parameters as a hashtable. .PARAMETER Connection The VergeConnection object to use. Defaults to the current default connection. .EXAMPLE Invoke-VergeAPI -Method GET -Endpoint 'vms' .EXAMPLE Invoke-VergeAPI -Method POST -Endpoint 'vm_actions' -Body @{ action = 'poweron'; vm = 123 } .NOTES This is an internal function and should not be called directly by users. #> [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateSet('GET', 'POST', 'PUT', 'DELETE', 'PATCH')] [string]$Method, [Parameter(Mandatory)] [string]$Endpoint, [Parameter()] [hashtable]$Body, [Parameter()] [hashtable]$Query, [Parameter()] [object]$Connection ) # Get connection if (-not $Connection) { $Connection = $script:DefaultConnection } if (-not $Connection) { throw [System.InvalidOperationException]::new( 'Not connected to VergeOS. Use Connect-VergeOS to establish a connection.' ) } if (-not $Connection.IsTokenValid()) { throw [System.InvalidOperationException]::new( "Session token is invalid or expired for '$($Connection.Server)'. Please reconnect." ) } # Build URI $uri = "$($Connection.ApiBaseUrl)/$Endpoint" # Add query parameters if ($Query -and $Query.Count -gt 0) { $queryParts = foreach ($key in $Query.Keys) { $encodedKey = [System.Uri]::EscapeDataString($key) $encodedValue = [System.Uri]::EscapeDataString($Query[$key]) "$encodedKey=$encodedValue" } $uri = "$uri`?$($queryParts -join '&')" } # Build authorization header based on auth type $authType = if ($Connection.AuthType) { $Connection.AuthType } else { 'Basic' } $authHeader = "$authType $($Connection.Token)" # Build request parameters $requestParams = @{ Method = $Method Uri = $uri Headers = @{ 'Authorization' = $authHeader 'Content-Type' = 'application/json' 'Accept' = 'application/json' } } # Add body for POST/PUT/PATCH if ($Body -and $Method -in @('POST', 'PUT', 'PATCH')) { $requestParams['Body'] = ($Body | ConvertTo-Json -Depth 10 -Compress) } # Handle certificate validation if ($Connection.SkipCertificateCheck) { $requestParams['SkipCertificateCheck'] = $true } # Make the request Write-Verbose "[$Method] $uri" try { $response = Invoke-RestMethod @requestParams -ErrorAction Stop return $response } catch { $statusCode = $_.Exception.Response.StatusCode.value__ $errorMessage = $_.ErrorDetails.Message # Try to parse error response if ($errorMessage) { try { $errorObj = $errorMessage | ConvertFrom-Json # Check for error message in various fields (handle both string and bool 'err') if ($errorObj.err -and $errorObj.err -is [string]) { $errorMessage = $errorObj.err } elseif ($errorObj.error -and $errorObj.error -is [string]) { $errorMessage = $errorObj.error } elseif ($errorObj.message -and $errorObj.message -is [string]) { $errorMessage = $errorObj.message } elseif ($errorObj.err -eq $true -and $errorObj.message) { $errorMessage = $errorObj.message } # Keep original error message if no string found } catch { # Keep original error message } } $fullError = "VergeOS API Error [$statusCode]: $errorMessage" switch ($statusCode) { 401 { throw [System.UnauthorizedAccessException]::new($fullError) } 403 { throw [System.UnauthorizedAccessException]::new($fullError) } 404 { throw [System.Management.Automation.ItemNotFoundException]::new($fullError) } default { throw [System.Net.Http.HttpRequestException]::new($fullError) } } } } |