There are better ways to do this. I'm still learning.
I have a generic class to facilitate querying GitHub's REST and GraphQL APIs:
class GitHub
{
/**
* API
* Make request to GitHub using the standard REST API.
* See: https://docs.github.com/en/rest
*
* @param [CurlHandle Object] $ch - curl handle
* @param [string] $endpoint - the REST endpoint
* @return array|stdClass
*/
public static function api(\CurlHandle $ch, string $endpoint)
{
curl_setopt($ch, CURLOPT_URL, 'https://api.github.com/'.$endpoint);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
$content = curl_exec($ch);
if (curl_errno($ch)) {
die("Error:".curl_error($ch));
}
return json_decode($content);
}
/**
* GraphQL
* Make request to GitHub using the newer GraphQL API.
* See: https://docs.github.com/en/graphql/reference
* GraphQL Explorer: https://docs.github.com/en/graphql/overview/explorer
* GraphQL Formatter: https://jsonformatter.org/graphql-formatter
*
* @param CurlHandle $ch
* @param string $query - a GraphQL query string
* @param array $variables - an array of GraphQL variables
* @return StdClass
*/
public static function graphQL(\CurlHandle $ch, string $query, array $variables)
{
curl_setopt($ch, CURLOPT_URL, 'https://api.github.com/graphql');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt(
$ch,
CURLOPT_POSTFIELDS,
json_encode(['query' => $query, 'variables' => $variables])
);
$content = curl_exec($ch);
if (curl_errno($ch)) {
die("Error:".curl_error($ch));
}
return json_decode($content);
}
}
Note that it's best practice to pass through parameters as a separate variables object.
Here's a working class to query ProjectsV2:
class GitHubProjects
{
/**
* getFirstN - get first N projects for the GitHub organisation, ordered by
* title
*
* @param \CurlHandle $ch
* @param integer $count - number of projects to return
* @return array
*/
public static function getFirstN(\CurlHandle $ch, int $count = 20): array
{
$projects = GitHub::graphQL(
$ch,
<<<EOD
query getFirstN(\$count: Int) {
organization(login: "Intech-Ltd") {
projectsV2(first: \$count, orderBy: {field: TITLE, direction: ASC}) {
nodes {
number
id
title
}
}
}
}
EOD,
[ "count" => $count ]
);
return $projects->data->organization->projectsV2->nodes;
}
/**
* getFirstNIssues
*
* @param \CurlHandle $ch
* @param integer $projectNumber
* @param integer $count
* @return array
*/
public static function getFirstNIssues(\CurlHandle $ch, int $projectNumber = 1, int $count = 20): array
{
$projectId = GitHubProjects::getIdByNumber($ch, $projectNumber);
$issues = GitHub::graphQL(
$ch,
<<<EOD
# Exclamation mark since projectId is required
query getFirstNIssues(\$projectId: ID!, \$count: Int) {
node(id: \$projectId) {
... on ProjectV2 {
items(first: \$count) {
nodes {
id
fieldValues(first: 8) {
nodes {
... on ProjectV2ItemFieldTextValue {
text
field {
... on ProjectV2FieldCommon {
name
}
}
}
... on ProjectV2ItemFieldDateValue {
date
field {
... on ProjectV2FieldCommon {
name
}
}
}
... on ProjectV2ItemFieldSingleSelectValue {
name
field {
... on ProjectV2FieldCommon {
name
}
}
}
}
}
content {
... on DraftIssue {
title
body
}
... on Issue {
title
assignees(first: 10) {
nodes {
login
}
}
}
... on PullRequest {
title
assignees(first: 10) {
nodes {
login
}
}
}
}
}
}
}
}
}
EOD,
[
"projectId" => $projectId,
"count" => $count
]
);
return $issues->data->node->items->nodes;
}
/**
* getByTitle - search for projects by title
*
* @param \CurlHandle $ch
* @param string $title - search for
* @return array
*/
public static function getByTitle(\CurlHandle $ch, string $title): array
{
$projects = GitHub::graphQL(
$ch,
<<<EOD
query getByName(\$title: String!) {
organization(login: "Intech-Ltd") {
projectsV2(
first: 20
orderBy: { field: TITLE, direction: ASC }
query: \$title
) {
nodes {
number
id
title
}
}
}
}
EOD,
[ "title" => $title ]
);
return $projects->data->organization->projectsV2->nodes;
}
/**
* getIdByNumber
*
* @param \CurlHandle $ch
* @param integer $number - the integer identifier of the project
* @return string - the internal GitHub project ID (e.g. PVT_kwDOBWQiz84AH53W)
*/
private static function getIdByNumber(\CurlHandle $ch, int $number = 1)
{
$project = GitHub::graphQL(
$ch,
<<<EOD
# Exclamation mark since number is required
query getIdByNumber(\$number: Int!) {
organization(login: "Intech-Ltd") {
projectV2(number: \$number) {
id
}
}
}
EOD,
['number' => $number]
);
return $project->data->organization->projectV2->id;
}
}
Example setting up cURL handler:
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Accept: application/vnd.github+json',
'Authorization: Bearer '.$_ENV['GH_TOKEN']
));
// Fake user agent, to keep GitHub happy
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0');
// Dev settings (PHP built-in server can't validate)
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
Generate a personal access token at: https://github.com/settings/tokens