Created
April 14, 2022 15:25
-
-
Save JingwenTian/a614c31107efccbac35b3a369708ba7d to your computer and use it in GitHub Desktop.
Produce the GraphQL query recommended for a full schema introspection.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
query IntrospectionQuery { | |
__schema { | |
queryType { | |
name | |
} | |
mutationType { | |
name | |
} | |
subscriptionType { | |
name | |
} | |
types { | |
...FullType | |
} | |
directives { | |
name | |
description | |
locations | |
args { | |
...InputValue | |
} | |
} | |
} | |
} | |
fragment FullType on __Type { | |
kind | |
name | |
description | |
fields(includeDeprecated: true) { | |
name | |
description | |
args { | |
...InputValue | |
} | |
type { | |
...TypeRef | |
} | |
isDeprecated | |
deprecationReason | |
} | |
inputFields { | |
...InputValue | |
} | |
interfaces { | |
...TypeRef | |
} | |
enumValues(includeDeprecated: true) { | |
name | |
description | |
isDeprecated | |
deprecationReason | |
} | |
possibleTypes { | |
...TypeRef | |
} | |
} | |
fragment InputValue on __InputValue { | |
name | |
description | |
type { | |
...TypeRef | |
} | |
defaultValue | |
} | |
fragment TypeRef on __Type { | |
kind | |
name | |
ofType { | |
kind | |
name | |
ofType { | |
kind | |
name | |
ofType { | |
kind | |
name | |
ofType { | |
kind | |
name | |
ofType { | |
kind | |
name | |
ofType { | |
kind | |
name | |
ofType { | |
kind | |
name | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} |
<?php
ini_set ('memory_limit', '6000M');
class Client
{
private $url;
private $query;
public function __construct(string $url, string $query = '')
{
$this->url = $url;
$this->query = $query;
}
public function run()
{
$data = $this->curl($this->url);
$schema = $data['data']['__schema'] ?? [];
if (!$schema) throw new \Exception("can't get schema");
$queryTypeName = $schema['queryType']['name'] ?? '';
if (!$queryTypeName) throw new \Exception("can't get query type name");
$queryType = $this->_findTypeByName($schema['types'], $queryTypeName);
if (!$queryType) throw new \Exception("can't get query type");
$rqQueryName = $this->_parseQueryName();
$queryObject = $this->_findTypeByName($queryType['fields'], $rqQueryName);
if (!$queryObject) throw new \Exception("can't find query $rqQueryName");
$responseType = $this->_findResponseType($queryObject['type']);
if (!$responseType) throw new \Exception("can't find response type for query ${rqQueryName}");
$responseObject = $this->_findTypeByName($schema['types'], $responseType);
if (!$responseObject) throw new \Exception("can't find response for type ${responseType}");
// var_dump($rqQueryName, $queryObject, $responseType, $responseObject);
$q = $this->_buildQuery($schema, $responseObject);
if (!$q) throw new \Exception("can't build query for ${rqQueryName}");
echo $q . PHP_EOL;
$response = $this->curl($this->url, $q);
if (!$response) throw new \Exception("no response from query ${rqQueryName})");
return $response;
}
private function _findTypeByName($types, $name) {
if ($types) {
$found = array_filter($types, function($type) use ($name) {
return $type['name'] === $name;
});
$found = array_values($found);
return count($found) === 1 ? $found[0] : null;
}
}
private function _parseQueryName() {
return explode('(', $this->query)[0] ?? null;
}
private function _findResponseType($type) {
if ($type) {
if (isset($type['name']) && !empty($type['name'])) {
return $type['name'];
}
if (isset($type['ofType']) && !empty($type['ofType'])) {
return $this->_findResponseType($type['ofType']);
}
}
}
private function _buildQuery($schema, $type) {
// return `query { ${this.query} ${this._buildFields(schema, type)}}`;
return sprintf('query { %s %s }', $this->query, $this->_buildFields($schema, $type));
}
private function _findResponseKind($type) {
if ($type) {
if (isset($type['kind']) && !empty($type['kind']) && $type['kind'] !== 'NON_NULL') {
return $type['kind'];
}
if (isset($type['ofType']) && !empty($type['ofType'])) {
return $this->_findResponseKind($type['ofType']);
}
}
}
private function _buildFields($schema, $type) {
$q = "";
if (isset($type['fields']) && !empty($type['fields'])) {
$q .= "{ ";
foreach ($type['fields'] as $field) {
$q .= $field['name'];
$kind = $this->_findResponseKind($field['type']);
switch ($kind) {
case 'LIST':
case 'OBJECT':
$lName = $this->_findResponseType($field['type']);
$lType = $this->_findTypeByName($schema['types'], $lName);
$q .= $this->_buildFields($schema, $lType);
break;
}
}
$q .= "} ";
}
return $q;
}
private function curl(string $endpoint, string $query = '', string $variables = null)
{
$schemaQuery = <<<GQL
query IntrospectionQuery {
__schema {
queryType {
name
}
mutationType {
name
}
subscriptionType {
name
}
types {
...FullType
}
directives {
name
description
locations
args {
...InputValue
}
}
}
}
fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}
fragment InputValue on __InputValue {
name
description
type {
...TypeRef
}
defaultValue
}
fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
}
}
}
}
GQL;
$query = $query ?: $schemaQuery;
$json = json_encode(['query' => $query, 'variables' => $variables]);
$headers = [];
$headers[] = 'Content-Type: application/json';
// $headers[] = 'Authorization: Bearer '.$authToken;
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $endpoint,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => $json,
CURLOPT_HTTPHEADER => $headers,
]);
$response = curl_exec($curl);
return json_decode($response, true);
}
}
$client = new Client('https://mirror-api.com/graphql', "topEntries()");
$client->run();
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@see https://github.com/graphql/graphql-js/blob/main/src/utilities/getIntrospectionQuery.ts
@see https://github.com/hoop33/gqall