Skip to content

Commit 5b41769

Browse files
authored
Fix schema built from SDL to return null for unknown types (#1068)
1 parent 5e72999 commit 5b41769

File tree

6 files changed

+40
-14
lines changed

6 files changed

+40
-14
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ You can find and compare releases at the [GitHub release page](https://github.co
6868
- Preserve extended methods from class-based types in `SchemaExtender::extend()`
6969
- Fix printing of empty types (#940)
7070
- Clone `NodeList` in `Node::cloneDeep()`
71+
- Calling `Schema::getType()` on a schema built from SDL returns `null` for unknown types (#1068)
7172

7273
### Removed
7374

src/Utils/ASTDefinitionBuilder.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
use GraphQL\Type\Definition\Type;
3535
use GraphQL\Type\Definition\UnionType;
3636
use function is_array;
37-
use function is_string;
3837
use Throwable;
3938

4039
/**
@@ -162,6 +161,19 @@ public function buildType($ref): Type
162161
return $this->internalBuildType($ref->name->value, $ref);
163162
}
164163

164+
/**
165+
* Calling this method is an equivalent of `typeMap[typeName]` in `graphql-js`.
166+
* It is legal to access a type from the map of already-built types that doesn't exist in the map.
167+
* Since we build types lazily, and we don't have a such map of built types,
168+
* this method provides a way to build a type that may not exist in the SDL definitions and returns null instead.
169+
*/
170+
public function maybeBuildType(string $name): ?Type
171+
{
172+
return isset($this->typeDefinitionsMap[$name])
173+
? $this->buildType($name)
174+
: null
175+
}
176+
165177
/**
166178
* @param (Node&NamedTypeNode)|(Node&TypeDefinitionNode)|null $typeNode
167179
*

src/Utils/BuildSchema.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,14 +156,14 @@ public function buildSchema(): Schema
156156
$operationTypes = null !== $schemaDef
157157
? $this->getOperationTypes($schemaDef)
158158
: [
159-
'query' => isset($this->nodeMap['Query']) ? 'Query' : null,
160-
'mutation' => isset($this->nodeMap['Mutation']) ? 'Mutation' : null,
161-
'subscription' => isset($this->nodeMap['Subscription']) ? 'Subscription' : null,
159+
'query' => 'Query',
160+
'mutation' => 'Mutation',
161+
'subscription' => 'Subscription',
162162
];
163163

164164
$definitionBuilder = new ASTDefinitionBuilder(
165165
$this->nodeMap,
166-
static function (string $typeName): void {
166+
static function (string $typeName): Type {
167167
throw self::unknownType($typeName);
168168
},
169169
$this->typeConfigDecorator
@@ -198,15 +198,15 @@ static function (string $typeName): void {
198198

199199
return new Schema([
200200
'query' => isset($operationTypes['query'])
201-
? $definitionBuilder->buildType($operationTypes['query'])
201+
? $definitionBuilder->maybeBuildType($operationTypes['query'])
202202
: null,
203203
'mutation' => isset($operationTypes['mutation'])
204-
? $definitionBuilder->buildType($operationTypes['mutation'])
204+
? $definitionBuilder->maybeBuildType($operationTypes['mutation'])
205205
: null,
206206
'subscription' => isset($operationTypes['subscription'])
207-
? $definitionBuilder->buildType($operationTypes['subscription'])
207+
? $definitionBuilder->maybeBuildType($operationTypes['subscription'])
208208
: null,
209-
'typeLoader' => static fn (string $name): Type => $definitionBuilder->buildType($name),
209+
'typeLoader' => static fn (string $name): ?Type => $definitionBuilder->maybeBuildType($name),
210210
'directives' => $directives,
211211
'astNode' => $schemaDef,
212212
'types' => fn (): array => array_map(

src/Utils/SchemaExtender.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -580,11 +580,7 @@ public static function extend(
580580
? $def->name->value
581581
: null;
582582

583-
try {
584-
$type = $schema->getType($typeName);
585-
} catch (Error $error) {
586-
$type = null;
587-
}
583+
$type = $schema->getType($typeName);
588584

589585
if (null !== $type) {
590586
throw new Error('Type "' . $typeName . '" already exists in the schema. It cannot also be defined in this type definition.', [$def]);

tests/Type/SchemaTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,12 @@ public function testIncludesInputTypesOnlyUsedInDirectives(): void
123123
self::assertArrayHasKey('DirInput', $typeMap);
124124
self::assertArrayHasKey('WrappedDirInput', $typeMap);
125125
}
126+
127+
/**
128+
* @see https://github.com/webonyx/graphql-php/issues/997
129+
*/
130+
public function testSchemaReturnsNullForNonexistentType(): void
131+
{
132+
self::assertNull($this->schema->getType('UnknownType'));
133+
}
126134
}

tests/Utils/BuildSchemaTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,15 @@ public function testThrowsOnUnknownTypes(): void
887887
', null, ['assumeValidSDL' => true])->assertValid();
888888
}
889889

890+
/**
891+
* @see https://github.com/webonyx/graphql-php/issues/997
892+
*/
893+
public function testBuiltSchemaReturnsNullForNonexistentType(): void
894+
{
895+
$schema = BuildSchema::build('type KnownType');
896+
self::assertNull($schema->getType('UnknownType'));
897+
}
898+
890899
public function testSupportsTypeConfigDecorator(): void
891900
{
892901
$body = '

0 commit comments

Comments
 (0)