Private/Errors.ps1

function New-DattoApiErrorRecord {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [int]$StatusCode,

        [Parameter(Mandatory)]
        [string]$ReasonPhrase,

        [Parameter(Mandatory)]
        [string]$Method,

        [Parameter(Mandatory)]
        [uri]$RequestUri,

        [Parameter()]
        [AllowNull()]
        [string]$ResponseText
    )

    $apiCode = $null
    $apiMessage = $null
    if (-not [string]::IsNullOrWhiteSpace($ResponseText)) {
        try {
            $errorBody = $ResponseText | ConvertFrom-Json -ErrorAction Stop
            if ($errorBody.PSObject.Properties.Name -contains 'code') { $apiCode = [string]$errorBody.code }
            if ($errorBody.PSObject.Properties.Name -contains 'message') { $apiMessage = [string]$errorBody.message }
        }
        catch { Write-Debug ('Datto error response was not JSON: {0}' -f $_.Exception.Message) }
    }

    $message = "Datto API request failed with HTTP $StatusCode ($ReasonPhrase) for $Method $($RequestUri.AbsolutePath)."
    if (-not [string]::IsNullOrWhiteSpace($apiMessage)) {
        $message += " $apiMessage"
    }
    if (-not [string]::IsNullOrWhiteSpace($apiCode)) {
        $message += " Datto code: $apiCode."
    }

    $exception = [System.Net.Http.HttpRequestException]::new($message)
    $exception.Data['StatusCode'] = $StatusCode
    $exception.Data['Method'] = $Method
    $exception.Data['RequestUri'] = $RequestUri.AbsoluteUri
    if ($null -ne $apiCode) { $exception.Data['DattoCode'] = $apiCode }

    switch ($StatusCode) {
        400 { $category = [System.Management.Automation.ErrorCategory]::InvalidArgument }
        401 { $category = [System.Management.Automation.ErrorCategory]::SecurityError }
        403 { $category = [System.Management.Automation.ErrorCategory]::PermissionDenied }
        404 { $category = [System.Management.Automation.ErrorCategory]::ObjectNotFound }
        408 { $category = [System.Management.Automation.ErrorCategory]::OperationTimeout }
        429 { $category = [System.Management.Automation.ErrorCategory]::ResourceBusy }
        default {
            if ($StatusCode -ge 500) { $category = [System.Management.Automation.ErrorCategory]::InvalidOperation }
            else { $category = [System.Management.Automation.ErrorCategory]::NotSpecified }
        }
    }

    $record = [System.Management.Automation.ErrorRecord]::new(
        $exception,
        ('DattoApi.Http.{0}' -f $StatusCode),
        $category,
        [pscustomobject]@{ Method = $Method; Uri = $RequestUri.AbsoluteUri; StatusCode = $StatusCode }
    )
    if (-not [string]::IsNullOrWhiteSpace($ResponseText)) {
        $record.ErrorDetails = [System.Management.Automation.ErrorDetails]::new($ResponseText)
    }
    return $record
}

function New-DattoApiTransportErrorRecord {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [System.Exception]$Exception,

        [Parameter(Mandatory)]
        [string]$Method,

        [Parameter(Mandatory)]
        [uri]$RequestUri
    )

    $message = "Datto API transport failure for $Method $($RequestUri.AbsolutePath): $($Exception.Message)"
    $wrapped = [System.Net.Http.HttpRequestException]::new($message, $Exception)
    $wrapped.Data['Method'] = $Method
    $wrapped.Data['RequestUri'] = $RequestUri.AbsoluteUri
    return [System.Management.Automation.ErrorRecord]::new(
        $wrapped,
        'DattoApi.TransportFailure',
        [System.Management.Automation.ErrorCategory]::ConnectionError,
        [pscustomobject]@{ Method = $Method; Uri = $RequestUri.AbsoluteUri }
    )
}