Functions/Private/Invoke-GitHubGraphQlApi.ps1
function Invoke-GitHubGraphQlApi { <# .Synopsis An internal function that is responsible for invoking the GitHub GraphQL endpoint. .Parameter Headers A HashTable of the HTTP request headers as key-value pairs. Some features in the GitHub API do not require any request headers, in which case this parameter should not be specified. NOTE: Do not include the HTTP Authorization header in this HashTable, as the Authorization header will be set by this function. .Parameter BaseUri Optional base URL of the GitHub API to resolve Uri from, for example "https://ghe.mycompany.com/api/v3/" (including the trailing slash). Defaults to "https://api.github.com". .Parameter Token The GitHub OAuth token to use for authenticating the request. Create one at https://github.com/settings/tokens/new. Not all requests require a token. #> [CmdletBinding()] param ( [Parameter(Mandatory, Position = 0)] [string] $Query, $Variables = @{ }, [Uri] $BaseUri = [Uri]::new('https://api.github.com'), # HTTP headers [HashTable] $Headers = @{ }, [Security.SecureString] $Token ) process { $Headers['User-Agent'] = 'PowerShell PSGitHub' # Resolve the Uri parameter with https://api.github.com as a base URI # This allows to call this function with just a path, # but also supply a full URI (e.g. for a GitHub enterprise instance) $Uri = [Uri]::new($BaseUri, 'graphql') $apiRequest = @{ Headers = $Headers Uri = $Uri Method = 'POST' } # add the HTTP Authorization header to authenticate the HTTP request. if ($Token) { $apiRequest.Authentication = 'Bearer' $apiRequest.Token = $Token } else { Write-Verbose -Message 'Making request without API token' } $body = @{ query = $Query variables = $Variables } $apiRequest.Body = $body | ConvertTo-Json -Depth 100 Write-Debug ("Query: " + $Query) Write-Debug ("Variables: " + $Variables) # We need to communicate using TLS 1.2 against GitHub. [Net.ServicePointManager]::SecurityProtocol = 'tls12' # Invoke the REST API try { $result = Invoke-RestMethod @apiRequest -ResponseHeadersVariable responseHeaders if ($responseHeaders.ContainsKey('X-RateLimit-Limit')) { Write-Verbose "Rate limit total: $($responseHeaders['X-RateLimit-Limit'])" Write-Verbose "Rate limit remaining: $($responseHeaders['X-RateLimit-Remaining'])" $resetUnixSeconds = [int]($responseHeaders['X-RateLimit-Reset'][0]) $resetDateTime = ([System.DateTimeOffset]::FromUnixTimeSeconds($resetUnixSeconds)).DateTime Write-Verbose "Rate limit resets: $resetDateTime" } if ($result.errors) { $result.errors | ForEach-Object message | Write-Error } $result.data } catch { if ( $_.Exception.PSObject.TypeNames -notcontains 'Microsoft.PowerShell.Commands.HttpResponseException' -and # PowerShell Core $_.Exception -isnot [System.Net.WebException] # Windows PowerShell ) { # Throw any error that is not a HTTP response error (e.g. server not reachable) throw $_ } # This is the only way to get access to the response body for errors in old PowerShell versions. # PowerShell >=7.0 could use -SkipHttpErrorCheck with -StatusCodeVariable $_.ErrorDetails.Message | Write-Error } } } |