Skip to content

Commit ceeb8a3

Browse files
authored
Warn about orphaned object types (#491)
1 parent dac4c79 commit ceeb8a3

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

src/Executor/ReferenceExecutor.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,16 @@ protected function ensureValidRuntimeType(
13391339
);
13401340
}
13411341

1342+
if ($this->exeContext->schema->getType($runtimeType->name) === null) {
1343+
throw new InvariantViolation(
1344+
'Schema does not contain type "' . $runtimeType->name . '". ' .
1345+
'This can happen when an object type is only referenced indirectly through ' .
1346+
'abstract types and never directly through fields.' .
1347+
'List the type in the option "types" during schema construction, ' .
1348+
'see https://webonyx.github.io/graphql-php/type-system/schema/#configuration-options.'
1349+
);
1350+
}
1351+
13421352
if ($runtimeType !== $this->exeContext->schema->getType($runtimeType->name)) {
13431353
throw new InvariantViolation(
13441354
sprintf(

tests/Executor/AbstractTest.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,66 @@ public function testReturningInvalidValueFromResolveTypeYieldsUsefulError(): voi
441441
self::assertEquals($expected, $result->toArray(DebugFlag::INCLUDE_DEBUG_MESSAGE));
442442
}
443443

444+
public function testWarnsAboutOrphanedTypesWhenMissingType(): void
445+
{
446+
$fooObject = null;
447+
$fooInterface = new InterfaceType([
448+
'name' => 'FooInterface',
449+
'fields' => [
450+
'bar' => [
451+
'type' => Type::string(),
452+
],
453+
],
454+
'resolveType' => static function () use (&$fooObject): ?ObjectType {
455+
return $fooObject;
456+
},
457+
]);
458+
459+
$fooObject = new ObjectType([
460+
'name' => 'FooObject',
461+
'fields' => [
462+
'bar' => [
463+
'type' => Type::string(),
464+
],
465+
],
466+
'interfaces' => [$fooInterface],
467+
]);
468+
469+
$schema = new Schema([
470+
'query' => new ObjectType([
471+
'name' => 'Query',
472+
'fields' => [
473+
'foo' => [
474+
'type' => $fooInterface,
475+
'resolve' => static fn (): array => ['bar' => 'baz'],
476+
],
477+
],
478+
]),
479+
]);
480+
481+
$result = GraphQL::executeQuery($schema, '{ foo { bar } }');
482+
483+
$expected = [
484+
'data' => ['foo' => null],
485+
'errors' => [
486+
[
487+
'message' => 'Internal server error',
488+
'locations' => [['line' => 1, 'column' => 3]],
489+
'path' => ['foo'],
490+
'extensions' => [
491+
'debugMessage' =>
492+
'Schema does not contain type "FooObject". ' .
493+
'This can happen when an object type is only referenced indirectly through ' .
494+
'abstract types and never directly through fields.' .
495+
'List the type in the option "types" during schema construction, ' .
496+
'see https://webonyx.github.io/graphql-php/type-system/schema/#configuration-options.',
497+
],
498+
],
499+
],
500+
];
501+
self::assertEquals($expected, $result->toArray(DebugFlag::INCLUDE_DEBUG_MESSAGE));
502+
}
503+
444504
/**
445505
* @see it('resolveType allows resolving with type name')
446506
*/

0 commit comments

Comments
 (0)