Skip to content

Commit 80f9739

Browse files
authored
fix: raise request error on invalid fragment variables (#4799)
1 parent 9c68b2a commit 80f9739

3 files changed

Lines changed: 38 additions & 2 deletions

File tree

src/execution/__tests__/variables-test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,6 +1609,27 @@ describe('Execute: Handles inputs', () => {
16091609
});
16101610
});
16111611

1612+
it('does not allow invalid types to be used as fragment variables', () => {
1613+
const result = executeQueryWithFragmentArguments(`
1614+
query {
1615+
...a
1616+
}
1617+
fragment a($value: TestType!) on TestType {
1618+
fieldWithNullableStringInput(input: $value)
1619+
}
1620+
`);
1621+
1622+
expectJSON(result).toDeepEqual({
1623+
errors: [
1624+
{
1625+
message:
1626+
'Variable "$value" expected value of type "TestType!" which cannot be used as an input type.',
1627+
locations: [{ line: 5, column: 28 }],
1628+
},
1629+
],
1630+
});
1631+
});
1632+
16121633
it('when a definition has a default, is not provided, and spreads another fragment', () => {
16131634
const result = executeQueryWithFragmentArguments(`
16141635
query {

src/execution/execute.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import type {
5151
import type { ExecutionResult } from './Executor.ts';
5252
import { Executor } from './Executor.ts';
5353
import { ExecutorThrowingOnIncremental } from './ExecutorThrowingOnIncremental.ts';
54+
import type { GraphQLVariableSignature } from './getVariableSignature.ts';
5455
import { getVariableSignature } from './getVariableSignature.ts';
5556
import type { ExperimentalIncrementalExecutionResults } from './incremental/IncrementalExecutor.ts';
5657
import { IncrementalExecutor } from './incremental/IncrementalExecutor.ts';
@@ -744,6 +745,7 @@ export function validateExecutionArgs(
744745
const fragmentDefinitions: ObjMap<FragmentDefinitionNode> =
745746
Object.create(null);
746747
const fragments: ObjMap<FragmentDetails> = Object.create(null);
748+
const fragmentVariableSignatureErrors: Array<GraphQLError> = [];
747749
for (const definition of document.definitions) {
748750
switch (definition.kind) {
749751
case Kind.OPERATION_DEFINITION:
@@ -764,11 +766,17 @@ export function validateExecutionArgs(
764766
fragmentDefinitions[definition.name.value] = definition;
765767
let variableSignatures;
766768
if (definition.variableDefinitions) {
767-
variableSignatures = Object.create(null);
769+
const signatures: ObjMap<GraphQLVariableSignature> =
770+
Object.create(null);
768771
for (const varDef of definition.variableDefinitions) {
769772
const signature = getVariableSignature(schema, varDef);
770-
variableSignatures[signature.name] = signature;
773+
if (signature instanceof GraphQLError) {
774+
fragmentVariableSignatureErrors.push(signature);
775+
continue;
776+
}
777+
signatures[signature.name] = signature;
771778
}
779+
variableSignatures = signatures;
772780
}
773781
fragments[definition.name.value] = { definition, variableSignatures };
774782
break;
@@ -785,6 +793,10 @@ export function validateExecutionArgs(
785793
return [new GraphQLError('Must provide an operation.')];
786794
}
787795

796+
if (fragmentVariableSignatureErrors.length > 0) {
797+
return fragmentVariableSignatureErrors;
798+
}
799+
788800
const variableDefinitions = operation.variableDefinitions ?? [];
789801
const hideSuggestions = args.hideSuggestions ?? false;
790802

src/utilities/__tests__/replaceVariables-test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { expect } from 'chai';
55
import { invariant } from '../../jsutils/invariant.ts';
66
import type { ReadOnlyObjMap } from '../../jsutils/ObjMap.ts';
77

8+
import { GraphQLError } from '../../error/GraphQLError.ts';
9+
810
import type {
911
FragmentArgumentNode,
1012
FragmentSpreadNode,
@@ -53,6 +55,7 @@ function testFragmentVariables(variableDefs: string, fragmentArgs: string) {
5355
const fragmentSignatures = Object.create(null);
5456
for (const varDef of parseVariableDefinitions(variableDefs)) {
5557
const signature = getVariableSignature(schema, varDef);
58+
invariant(!(signature instanceof GraphQLError));
5659
fragmentSignatures[signature.name] = signature;
5760
}
5861
const spread: FragmentSpreadNode = {

0 commit comments

Comments
 (0)