Skip to content

Commit 0a0e208

Browse files
authored
do not send variables with value undefined (#1455)
graphql-js converts these to null See graphql/graphql-js#2533
1 parent 21ff648 commit 0a0e208

File tree

8 files changed

+129
-46
lines changed

8 files changed

+129
-46
lines changed

src/Interfaces.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,12 @@ export interface ExecutionParams<TArgs = Record<string, any>, TContext = any> {
174174
context?: TContext;
175175
info?: GraphQLResolveInfo;
176176
}
177-
export type Executor = (params: ExecutionParams) => Promise<ExecutionResult> | ExecutionResult;
178-
export type Subscriber = (params: ExecutionParams) => Promise<AsyncIterator<ExecutionResult> | ExecutionResult>;
177+
export type Executor = (
178+
params: ExecutionParams,
179+
) => Promise<ExecutionResult> | ExecutionResult;
180+
export type Subscriber = (
181+
params: ExecutionParams,
182+
) => Promise<AsyncIterator<ExecutionResult> | ExecutionResult>;
179183

180184
export interface SubschemaConfig {
181185
schema: GraphQLSchema;
@@ -222,7 +226,10 @@ export interface IMakeRemoteExecutableSchemaOptions {
222226
schema: GraphQLSchema | string;
223227
executor?: Executor;
224228
subscriber?: Subscriber;
225-
createResolver?: (executor: Executor, subscriber: Subscriber) => GraphQLFieldResolver<any, any>;
229+
createResolver?: (
230+
executor: Executor,
231+
subscriber: Subscriber,
232+
) => GraphQLFieldResolver<any, any>;
226233
buildSchemaOptions?: BuildSchemaOptions;
227234
}
228235

src/delegate/createRequest.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,13 @@ export function createRequest({
113113
sourceSchema,
114114
def.type as NamedTypeNode,
115115
) as GraphQLInputType;
116-
newVariables[varName] = serializeInputValue(
116+
const serializedValue = serializeInputValue(
117117
varType,
118118
variableValues[varName],
119119
);
120+
if (serializedValue !== undefined) {
121+
newVariables[varName] = serializedValue;
122+
}
120123
});
121124
}
122125

src/delegate/transforms/FilterToSchema.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,10 @@ function filterToSchema(
142142
});
143143

144144
const newVariables = usedVariables.reduce((acc, variableName) => {
145-
acc[variableName] = variables[variableName];
145+
const variableValue = variables[variableName];
146+
if (variableValue !== undefined) {
147+
acc[variableName] = variableValue;
148+
}
146149
return acc;
147150
}, {});
148151

src/stitch/typeFromAST.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ function makeValues(
188188
[node.name.value]: {
189189
type: createStub(node.type, 'input'),
190190
defaultValue:
191-
node.defaultValue != null
191+
node.defaultValue !== undefined
192192
? valueFromASTUntyped(node.defaultValue)
193193
: undefined,
194194
description: getDescription(node, backcompatOptions),

src/test/alternateStitchSchemas.test.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,83 @@ describe('transform object fields', () => {
426426
});
427427
});
428428

429+
describe('optional arguments', () => {
430+
const schema = makeExecutableSchema({
431+
typeDefs: `
432+
enum Arg {
433+
possibleArg
434+
}
435+
type Query {
436+
test(arg: Arg): Boolean
437+
}
438+
`,
439+
resolvers: {
440+
Query: {
441+
test: (_root, args, _context) => args.arg === undefined,
442+
},
443+
},
444+
});
445+
446+
const stitchedSchema = stitchSchemas({
447+
schemas: [schema],
448+
});
449+
450+
it('work with schema stitching', async () => {
451+
const query = `
452+
{
453+
test
454+
}
455+
`;
456+
457+
const originalResult = await graphql(schema, query);
458+
expect(originalResult.data.test).toEqual(true);
459+
460+
const stitchedResult = await graphql(stitchedSchema, query);
461+
expect(stitchedResult.data.test).toEqual(true);
462+
});
463+
464+
it('work with schema stitching when using variables', async () => {
465+
const query = `
466+
query test($arg: Arg) {
467+
test(arg: $arg)
468+
}
469+
`;
470+
471+
const originalResult = await graphql(schema, query);
472+
expect(originalResult.data.test).toEqual(true);
473+
474+
const stitchedResult = await graphql(stitchedSchema, query);
475+
expect(stitchedResult.data.test).toEqual(true);
476+
});
477+
478+
// See https://github.com/graphql/graphql-js/issues/2533
479+
it('may not work as expected when explicitly passing in an undefined value', async () => {
480+
const query = `
481+
query test($arg: Arg) {
482+
test(arg: $arg)
483+
}
484+
`;
485+
486+
const originalResult = await graphql(
487+
schema,
488+
query,
489+
{},
490+
{},
491+
{ arg: undefined },
492+
);
493+
expect(originalResult.data.test).toEqual(false);
494+
495+
const stitchedResult = await graphql(
496+
stitchedSchema,
497+
query,
498+
{},
499+
{},
500+
{ arg: undefined },
501+
);
502+
expect(stitchedResult.data.test).toEqual(false);
503+
});
504+
});
505+
429506
describe('default values', () => {
430507
test('should work to add a default value even when renaming root fields', async () => {
431508
const transformedPropertySchema = transformSchema(propertySchema, [

src/test/fixtures/schemas.ts

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ const propertyRootTypeDefs = `
297297
testString: String
298298
bar: String
299299
}`
300-
: `type TestImpl2 implements TestInterface {
300+
: `type TestImpl2 implements TestInterface {
301301
kind: TestInterfaceKind
302302
testString: String
303303
bar: String
@@ -364,27 +364,27 @@ const propertyResolvers: IResolvers = {
364364
interfaceTest(_root, { kind }) {
365365
return kind === 'ONE'
366366
? {
367-
kind: 'ONE',
368-
testString: 'test',
369-
foo: 'foo',
370-
}
367+
kind: 'ONE',
368+
testString: 'test',
369+
foo: 'foo',
370+
}
371371
: {
372-
kind: 'TWO',
373-
testString: 'test',
374-
bar: 'bar',
375-
};
372+
kind: 'TWO',
373+
testString: 'test',
374+
bar: 'bar',
375+
};
376376
},
377377

378378
unionTest(_root, { output }) {
379379
return output === 'Interface'
380380
? {
381-
kind: 'ONE',
382-
testString: 'test',
383-
foo: 'foo',
384-
}
381+
kind: 'ONE',
382+
testString: 'test',
383+
foo: 'foo',
384+
}
385385
: {
386-
someField: 'Bar',
387-
};
386+
someField: 'Bar',
387+
};
388388
},
389389

390390
errorTest() {
@@ -680,23 +680,13 @@ export const subscriptionSchema: GraphQLSchema = makeExecutableSchema({
680680
});
681681

682682
function makeExecutorFromSchema(schema: GraphQLSchema): Executor {
683-
return async ({ document, variables, context }) => graphql(
684-
schema,
685-
print(document),
686-
null,
687-
context,
688-
variables,
689-
);
683+
return async ({ document, variables, context }) =>
684+
graphql(schema, print(document), null, context, variables);
690685
}
691686

692687
function makeSubscriberFromSchema(schema: GraphQLSchema): Subscriber {
693-
return async ({ document, variables, context }) => subscribe(
694-
schema,
695-
document,
696-
null,
697-
context,
698-
variables,
699-
)
688+
return async ({ document, variables, context }) =>
689+
subscribe(schema, document, null, context, variables);
700690
}
701691

702692
export async function makeSchemaRemote(
@@ -713,9 +703,5 @@ export async function makeSchemaRemote(
713703
}
714704

715705
export const remotePropertySchema = makeSchemaRemote(propertySchema);
716-
export const remoteProductSchema = makeSchemaRemote(
717-
productSchema,
718-
);
719-
export const remoteBookingSchema = makeSchemaRemote(
720-
bookingSchema,
721-
);
706+
export const remoteProductSchema = makeSchemaRemote(productSchema);
707+
export const remoteBookingSchema = makeSchemaRemote(bookingSchema);

src/utils/updateArgument.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,9 @@ export function updateArgument(
4747
type: astFromType(argType),
4848
};
4949

50-
variableValues[varName] = newArg;
50+
if (newArg === undefined) {
51+
delete variableValues[varName];
52+
} else {
53+
variableValues[varName] = newArg;
54+
}
5155
}

src/wrap/transforms/MapFields.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@ export default class MapFields implements Transform {
1212
(_typeName, _fieldName, field) => ({
1313
description: field.deprecationReason,
1414
type: field.type,
15-
args: field.args.reduce<GraphQLFieldConfigArgumentMap>((prev, curr) => ({
16-
...prev,
17-
[curr.name]: curr,
18-
}), {}),
15+
args: field.args.reduce<GraphQLFieldConfigArgumentMap>(
16+
(prev, curr) => ({
17+
...prev,
18+
[curr.name]: curr,
19+
}),
20+
{},
21+
),
1922
resolve: field.resolve,
2023
subscribe: field.subscribe,
2124
deprecationReason: field.deprecationReason,

0 commit comments

Comments
 (0)