Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ You can find and compare releases at the [GitHub release page](https://github.co

## Unreleased

### Changed

- Allow omitting deprecated introspection arguments/fields for legacy servers https://github.com/webonyx/graphql-php/pull/1849

## v15.30.2

### Fixed
Expand Down
34 changes: 23 additions & 11 deletions src/Type/Introspection.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
* @phpstan-type IntrospectionOptions array{
* descriptions?: bool,
* directiveIsRepeatable?: bool,
* includeDeprecated?: bool,
* schemaDescription?: bool,
* typeIsOneOf?: bool,
* }
Expand All @@ -41,6 +42,12 @@
* - directiveIsRepeatable
* Include field `isRepeatable` for directives?
* Default: false
* - includeDeprecated
* Include deprecated fields/args/enum values/input fields and related indicators
* (isDeprecated/deprecationReason) in the introspection query
* Default: true
*
* @see https://graphql-ruby.org/api-doc/1.12.1/GraphQL/Introspection.html
* - typeIsOneOf
* Include field `isOneOf` for types?
* Default: false
Expand Down Expand Up @@ -86,6 +93,7 @@ public static function getIntrospectionQuery(array $options = []): string
$optionsWithDefaults = array_merge([
'descriptions' => true,
'directiveIsRepeatable' => false,
'includeDeprecated' => true,
'schemaDescription' => false,
'typeIsOneOf' => false,
], $options);
Expand All @@ -102,6 +110,13 @@ public static function getIntrospectionQuery(array $options = []): string
$typeIsOneOf = $optionsWithDefaults['typeIsOneOf']
? 'isOneOf'
: '';
$includeDeprecated = $optionsWithDefaults['includeDeprecated'];
$includeDeprecatedArg = $includeDeprecated
? '(includeDeprecated: true)'
: '';
$deprecationIndicators = $includeDeprecated
? " isDeprecated\n deprecationReason"
: '';

return <<<GRAPHQL
query IntrospectionQuery {
Expand All @@ -116,7 +131,7 @@ public static function getIntrospectionQuery(array $options = []): string
directives {
name
{$descriptions}
args(includeDeprecated: true) {
args{$includeDeprecatedArg} {
...InputValue
}
{$directiveIsRepeatable}
Expand All @@ -130,29 +145,27 @@ public static function getIntrospectionQuery(array $options = []): string
name
{$descriptions}
{$typeIsOneOf}
fields(includeDeprecated: true) {
fields{$includeDeprecatedArg} {
name
{$descriptions}
args(includeDeprecated: true) {
args{$includeDeprecatedArg} {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
{$deprecationIndicators}
}
inputFields(includeDeprecated: true) {
inputFields{$includeDeprecatedArg} {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
enumValues{$includeDeprecatedArg} {
name
{$descriptions}
isDeprecated
deprecationReason
{$deprecationIndicators}
}
possibleTypes {
...TypeRef
Expand All @@ -164,8 +177,7 @@ enumValues(includeDeprecated: true) {
{$descriptions}
type { ...TypeRef }
defaultValue
isDeprecated
deprecationReason
{$deprecationIndicators}
}

fragment TypeRef on __Type {
Expand Down
4 changes: 2 additions & 2 deletions src/Utils/BuildClientSchema.php
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ private function buildEnumDef(array $enum): EnumType
foreach ($enum['enumValues'] as $value) {
$values[$value['name']] = [
'description' => $value['description'],
'deprecationReason' => $value['deprecationReason'],
'deprecationReason' => $value['deprecationReason'] ?? null,
];
}

Expand Down Expand Up @@ -479,7 +479,7 @@ private function buildFieldDefMap(array $typeIntrospection): array

$map[$field['name']] = [
'description' => $field['description'],
'deprecationReason' => $field['deprecationReason'],
'deprecationReason' => $field['deprecationReason'] ?? null,
'type' => $this->getOutputType($field['type']),
'args' => $this->buildInputValueDefMap($field['args']),
];
Expand Down
22 changes: 22 additions & 0 deletions tests/Type/IntrospectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2020,4 +2020,26 @@ public function testIncludeDescriptionFieldOnSchema(): void
preg_match_all('/\bdescription\b/', Introspection::getIntrospectionQuery(['descriptions' => false, 'schemaDescription' => true]), $matches);
self::assertCount(0, $matches[0]);
}

public function testExcludeDeprecatedFieldsAndIndicatorsWhenDisabled(): void
{
$source = Introspection::getIntrospectionQuery(['includeDeprecated' => false]);

self::assertStringNotContainsString('includeDeprecated: true', $source);
self::assertStringNotContainsString('includeDeprecated: false', $source);
self::assertStringContainsString('args {', $source);
self::assertStringContainsString('fields {', $source);
self::assertStringContainsString('inputFields {', $source);
self::assertStringContainsString('enumValues {', $source);
self::assertStringNotContainsString('isDeprecated', $source);
self::assertStringNotContainsString('deprecationReason', $source);
}

/** @see it('keeps deprecated args enabled by default') */
public function testIncludeDeprecatedArgumentsByDefault(): void
{
$source = Introspection::getIntrospectionQuery();

self::assertStringContainsString('(includeDeprecated: true)', $source);
}
}
32 changes: 32 additions & 0 deletions tests/Utils/BuildClientSchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,38 @@ public function testUsesBuiltInScalarsWhenPossible(): void
);
}

public function testBuildsSchemaFromIntrospectionWithoutDeprecatedFields(): void
{
$sdl = '
type Query {
active: String
legacy: String @deprecated(reason: "Use active")
}

enum Status {
OK
OLD @deprecated(reason: "Use OK")
}
';

$schema = BuildSchema::build($sdl);
$introspection = Introspection::fromSchema($schema, [
'includeDeprecated' => false,
]);

$clientSchema = BuildClientSchema::build($introspection);

$queryType = $clientSchema->getQueryType();
self::assertNotNull($queryType);
self::assertArrayHasKey('active', $queryType->getFields());
self::assertArrayNotHasKey('legacy', $queryType->getFields());

$statusEnum = $clientSchema->getType('Status');
self::assertInstanceOf(EnumType::class, $statusEnum);
self::assertNotNull($statusEnum->getValue('OK'));
self::assertNull($statusEnum->getValue('OLD'));
}

/** it('includes standard types only if they are used', () => {. */
public function testIncludesStandardTypesOnlyIfTheyAreUsed(): void
{
Expand Down