Public/Invoke-DattoApiRequest.ps1
|
function Invoke-DattoApiRequest { <# .SYNOPSIS Invokes an authenticated request against a relative Datto REST API v1 path. .DESCRIPTION Provides the common request engine used by the endpoint-specific commands. It supports GET and PUT, safe URI construction, JSON request bodies, response parsing, automatic pagination, bounded retries, and access to raw response metadata. Only relative /v1/ paths are accepted so credentials cannot be redirected to another host. .PARAMETER Method GET or PUT. .PARAMETER Path A relative Datto API path beginning with /v1/. Do not include a query string. .PARAMETER Query A hashtable of query parameters. Enumerable values are encoded as comma-separated values. .PARAMETER Body An object to serialize as JSON for PUT requests. .PARAMETER All Retrieves all pages for a GET operation when the response contains pagination metadata. It is rejected for PUT operations. .PARAMETER ResultProperty The envelope property containing records, such as items or clients. Auto-detected when omitted. .PARAMETER RawResponse Returns the API response body rather than extracting records. With -All, returns an aggregated envelope with _dattoAggregation metadata. .PARAMETER IncludeResponseMetadata Returns status, headers, content type, and body for a single request. It cannot be combined with -All. .PARAMETER AsByteArray Returns response bytes. It cannot be combined with -All. .PARAMETER RetryNonIdempotent Allows automatic retries for PUT requests. Use only when the operation is known to be safe to repeat. .PARAMETER MaxPages Safety ceiling for automatic pagination. .PARAMETER Connection A connection object, name, or ID. .EXAMPLE Invoke-DattoApiRequest -Path '/v1/bcdr/device' -Query @{ _page = 1; _perPage = 100 } .EXAMPLE Invoke-DattoApiRequest -Path '/v1/bcdr/agent' -All -ResultProperty clients .EXAMPLE Invoke-DattoApiRequest -Method PUT -Path '/v1/dtc/agent/AGENT_UUID/bandwidth' -Body @{ pauseWhileMetered = $false } #> [CmdletBinding()] param( [Parameter()] [ValidateSet('GET', 'PUT')] [string]$Method = 'GET', [Parameter(Mandatory)] [ValidatePattern('^/v1/')] [string]$Path, [Parameter()] [AllowNull()] [System.Collections.IDictionary]$Query, [Parameter()] [AllowNull()] [object]$Body, [Parameter()] [switch]$All, [Parameter()] [ValidateNotNullOrEmpty()] [string]$ResultProperty, [Parameter()] [switch]$RawResponse, [Parameter()] [switch]$IncludeResponseMetadata, [Parameter()] [switch]$AsByteArray, [Parameter()] [switch]$RetryNonIdempotent, [Parameter()] [ValidateRange(1, 10000)] [int]$MaxPages = 1000, [Parameter()] [AllowNull()] [object]$Connection ) if ($Method -eq 'GET' -and $PSBoundParameters.ContainsKey('Body')) { throw [System.ArgumentException]::new('A request body is not supported for GET operations in the supplied Datto API contract.') } if ($All -and $Method -ne 'GET') { throw [System.ArgumentException]::new('-All is supported only for GET operations and will never repeat a state-changing PUT request.') } if ($All -and ($AsByteArray -or $IncludeResponseMetadata)) { throw [System.ArgumentException]::new('-All cannot be combined with -AsByteArray or -IncludeResponseMetadata.') } $queryCopy = Copy-DattoApiQuery -Query $Query $response = Invoke-DattoApiHttpRequest -Method $Method -Path $Path -Query $queryCopy -Body $Body -Connection $Connection -AsByteArray:$AsByteArray -RetryNonIdempotent:$RetryNonIdempotent if ($IncludeResponseMetadata) { return $response } if ($AsByteArray) { Write-Output -NoEnumerate $response.Bytes return } if (-not $All) { if ($RawResponse) { Write-Output -NoEnumerate $response.Body return } $resolved = Resolve-DattoApiResultCollection -Body $response.Body -ResultProperty $ResultProperty foreach ($value in $resolved.Values) { $value } return } $firstBody = $response.Body $resolvedFirst = Resolve-DattoApiResultCollection -Body $firstBody -ResultProperty $ResultProperty $pagination = Get-DattoApiPaginationObject -Body $firstBody if ($null -eq $pagination -or -not $resolvedFirst.IsEnvelope) { if ($RawResponse) { Write-Output -NoEnumerate $firstBody } else { foreach ($value in $resolvedFirst.Values) { $value } } return } $currentPage = 1 $totalPages = 1 if ($pagination.PSObject.Properties.Name -contains 'page') { $currentPage = [int]$pagination.page } if ($pagination.PSObject.Properties.Name -contains 'totalPages') { $totalPages = [int]$pagination.totalPages } if ($totalPages -lt $currentPage) { $totalPages = $currentPage } $pagesNeeded = ($totalPages - $currentPage) + 1 if ($pagesNeeded -gt $MaxPages) { throw [System.InvalidOperationException]::new("The response requires $pagesNeeded pages, which exceeds -MaxPages $MaxPages.") } $allValues = [System.Collections.Generic.List[object]]::new() foreach ($value in $resolvedFirst.Values) { $allValues.Add($value) } $firstPage = $currentPage $pagesRequested = 1 for ($page = $currentPage + 1; $page -le $totalPages; $page++) { $queryCopy['_page'] = $page $pageResponse = Invoke-DattoApiHttpRequest -Method $Method -Path $Path -Query $queryCopy -Body $Body -Connection $Connection -RetryNonIdempotent:$RetryNonIdempotent $pageResolved = Resolve-DattoApiResultCollection -Body $pageResponse.Body -ResultProperty $resolvedFirst.PropertyName foreach ($value in $pageResolved.Values) { $allValues.Add($value) } $pagesRequested++ } $values = [object[]]$allValues.ToArray() if ($RawResponse) { $envelope = New-DattoApiAggregatedEnvelope -FirstBody $firstBody -ResultProperty $resolvedFirst.PropertyName -Values $values -FirstPage $firstPage -LastPage $totalPages -PagesRequested $pagesRequested Write-Output -NoEnumerate $envelope } else { foreach ($value in $values) { $value } } } |