Private/InvokeAirTableApiCall.ps1

function InvokeAirTableApiCall {
    <#
        .SYNOPSIS
            A private function that crafts the REST call to AirTable.
    
        .EXAMPLE
            PS> InvokeAirTableApiCall -Uri 'https://api.airtable.com/v0/Fruit' -HttpBody @{ filterByFormula = "{Name}='Apple'" }

            Queries the AirTable URI and passes the HTTP body to the API using the GET method.

        .EXAMPLE
            PS> InvokeAirTableApiCall -Uri 'https://api.airtable.com/v0/Fruit' -HttpBody @{ filterByFormula = "{Name}='Apple'" } -Method POST

            Queries the AirTable URI and passes the HTTP body to the API using the POST method.

             .EXAMPLE
            PS> InvokeAirTableApiCall -Uri 'https://api.airtable.com/v0/Fruit' -HttpBody @{ filterByFormula = "{Name}='Apple'" } -Method POST -CharSet 'utf-8'

            Queries the AirTable URI and passes the HTTP body to the API using the POST method with charset 'utf-8'

        .PARAMETER Uri
            A string value representing the API endpoint URI.

        .PARAMETER HttpBody
            A hashtable value representing the HTTP body to send to the API.

        .PARAMETER Method
            A string value representing the HTTP verb (method) to send to the API. This defaults to using GET.
   
           .PARAMETER CharSet
                 A string value representing charset like utf-8, which is used for the http-request.
            Possible charsets:
            https://www.iana.org/assignments/character-sets/character-sets.xhtml
    
    #>

    [OutputType('pscustomobject')]
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$Uri,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [hashtable]$HttpBody,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$CharSet,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$Method = 'GET',

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$PersonalAccessToken = (Get-AirTablePersonalAccessToken)
    )

    $ErrorActionPreference = 'Stop'

    try {
        $headers = @{
            'Authorization' = "Bearer $PersonalAccessToken"
        }
        
        $invRestParams = @{
            Method             = $Method
            Headers            = $headers
            Uri                = $Uri
        }

        switch ($Method) {
            'GET' {
                if ($PSBoundParameters.ContainsKey('HttpBody')) {
                    $invRestParams.Body = $HttpBody
                }
                break
            }
            { $_ -in 'PATCH', 'POST', 'DELETE' } {
                if ($CharSet) {
                    $invRestParams.ContentType = 'application/json; charset=' + $CharSet
                } else {
                    $invRestParams.ContentType = 'application/json'
                }
                if ($PSBoundParameters.ContainsKey('HttpBody')) {
                    $invRestParams.Body = (ConvertTo-Json $HttpBody)
                }
                break
            }
            default {
                throw "Unrecognized input: [$_]"
            }
        }

        try {
            $response = Invoke-RestMethod @invRestParams
        } catch {
            if ('Response' -in $_.Exception.PSObject.Properties.Name) {
                $statusCode = $_.Exception.Response.StatusCode.Value__
                if ($statusCode -ne 200) {
                    $err = ($_.errordetails.message | ConvertFrom-Json).error
                    throw "The Airtable API returned a [$($err.type)] error with message: [$($err.message)]"
                }
            } else {
                throw $_
            }
        }
        
        if ('records' -in $response.PSObject.Properties.Name) {
            $baseId = $Uri.split('/')[4]
            $table = $Uri.split('/')[5]
            $response.records.foreach({
                    $output = $_.fields
                    $output | Add-Member -MemberType NoteProperty -Name 'Record ID' -Value $_.id
                    $output | Add-Member -MemberType NoteProperty -Name 'Base ID' -Value $baseId
                    $output | Add-Member -MemberType NoteProperty -Name 'Table' -Value $table -PassThru
                })
            
            while ('offset' -in $response.PSObject.Properties.Name) {
                $invParams = [hashtable]$PSBoundParameters
                if ($invParams['HttpBody'] -and $invParams['HttpBody'].ContainsKey('offset')) {
                    $invParams['HttpBody'].offset = $response.offset
                } else {
                    $invParams['HttpBody'] = $HttpBody + @{ offset = $response.offset }
                }
                
                InvokeAirTableApiCall @invParams | Tee-Object -Variable response
            }
        } elseif ('fields' -in $response.PSObject.Properties.Name) {
            $baseId = $Uri.split('/')[4]
            $table = $Uri.split('/')[5]
            $output = $response.fields
            $output | Add-Member -MemberType NoteProperty -Name 'Record ID' -Value $response.id
            $output | Add-Member -MemberType NoteProperty -Name 'Base ID' -Value $baseId
            $output | Add-Member -MemberType NoteProperty -Name 'Table' -Value $table -PassThru
        }
    } catch {
        $PSCmdlet.ThrowTerminatingError($_)
    }
}