diff --git a/src/Interfaces.ts b/src/Interfaces.ts index ea89da03f96..4fba105a2d9 100644 --- a/src/Interfaces.ts +++ b/src/Interfaces.ts @@ -115,7 +115,7 @@ export function isSubschemaConfig(value: SchemaLikeObject): value is SubschemaCo export interface IDelegateToSchemaOptions { schema: GraphQLSchema | SubschemaConfig; - operation: Operation; + operation?: Operation; fieldName: string; returnType?: GraphQLOutputType; args?: { [key: string]: any }; @@ -124,7 +124,7 @@ export interface IDelegateToSchemaOptions { rootValue?: Record; transforms?: Array; skipValidation?: boolean; - mergeTypes?: boolean; + skipTypeMerging?: boolean; } export interface ICreateDelegatingRequestOptions { @@ -147,7 +147,7 @@ export interface IDelegateRequestOptions { returnType?: GraphQLOutputType; context?: TContext; transforms?: Array; - mergeTypes?: boolean; + skipTypeMerging?: boolean; } export type Delegator = ({ document, context, variables }: { diff --git a/src/stitching/checkResultAndHandleErrors.ts b/src/stitching/checkResultAndHandleErrors.ts index 504464deb4f..ecf6b3a3681 100644 --- a/src/stitching/checkResultAndHandleErrors.ts +++ b/src/stitching/checkResultAndHandleErrors.ts @@ -36,7 +36,7 @@ export function checkResultAndHandleErrors( responseKey?: string, subschema?: GraphQLSchema | SubschemaConfig, returnType: GraphQLOutputType = info.returnType, - mergeTypes?: boolean, + skipTypeMerging?: boolean, ): any { if (!responseKey) { responseKey = getResponseKeyFromInfo(info); @@ -46,7 +46,7 @@ export function checkResultAndHandleErrors( const data = result.data && result.data[responseKey]; const subschemas = [subschema]; - return handleResult(data, errors, subschemas, context, info, returnType, mergeTypes); + return handleResult(data, errors, subschemas, context, info, returnType, skipTypeMerging); } export function handleResult( @@ -56,7 +56,7 @@ export function handleResult( context: Record, info: IGraphQLToolsResolveInfo, returnType = info.returnType, - mergeTypes?: boolean, + skipTypeMerging?: boolean, ): any { const type = getNullableType(returnType); @@ -67,9 +67,9 @@ export function handleResult( if (isLeafType(type)) { return type.parseValue(result); } else if (isCompositeType(type)) { - return handleObject(type, result, errors, subschemas, context, info, mergeTypes); + return handleObject(type, result, errors, subschemas, context, info, skipTypeMerging); } else if (isListType(type)) { - return handleList(type, result, errors, subschemas, context, info, mergeTypes); + return handleList(type, result, errors, subschemas, context, info, skipTypeMerging); } } @@ -95,11 +95,12 @@ export function handleObject( subschemas: Array, context: Record, info: IGraphQLToolsResolveInfo, - mergeTypes?: boolean, + skipTypeMerging?: boolean, ) { makeObjectProxiedResult(object, errors, subschemas); - - if (mergeTypes && info.mergeInfo) { + if (skipTypeMerging || !info.mergeInfo) { + return object; + } else { return mergeFields( type, object, @@ -107,8 +108,6 @@ export function handleObject( context, info, ); - } else { - return object; } } @@ -119,9 +118,8 @@ function handleList( subschemas: Array, context: Record, info: IGraphQLToolsResolveInfo, - mergeTypes?: boolean, + skipTypeMerging?: boolean, ) { - const childErrors = getErrorsByPathSegment(errors); list = list.map((listMember, index) => handleListMember( @@ -132,7 +130,7 @@ function handleList( subschemas, context, info, - mergeTypes, + skipTypeMerging, )); return list; @@ -146,7 +144,7 @@ function handleListMember( subschemas: Array, context: Record, info: IGraphQLToolsResolveInfo, - mergeTypes?: boolean, + skipTypeMerging?: boolean, ): any { if (listMember == null) { return handleNull(info.fieldNodes, [...responsePathAsArray(info.path), index], errors); @@ -155,9 +153,9 @@ function handleListMember( if (isLeafType(type)) { return type.parseValue(listMember); } else if (isCompositeType(type)) { - return handleObject(type, listMember, errors, subschemas, context, info, mergeTypes); + return handleObject(type, listMember, errors, subschemas, context, info, skipTypeMerging); } else if (isListType(type)) { - return handleList(type, listMember, errors, subschemas, context, info, mergeTypes); + return handleList(type, listMember, errors, subschemas, context, info, skipTypeMerging); } } diff --git a/src/stitching/defaultMergedResolver.ts b/src/stitching/defaultMergedResolver.ts index 6f98e80a15b..bec11fd249b 100644 --- a/src/stitching/defaultMergedResolver.ts +++ b/src/stitching/defaultMergedResolver.ts @@ -30,5 +30,5 @@ export default function defaultMergedResolver( const result = parent[responseKey]; const subschemas = getSubschemas(parent); - return handleResult(result, errors, subschemas, context, info, undefined, true); + return handleResult(result, errors, subschemas, context, info); } diff --git a/src/stitching/delegateToSchema.ts b/src/stitching/delegateToSchema.ts index 2cf4e0d1cba..0d52be6c394 100644 --- a/src/stitching/delegateToSchema.ts +++ b/src/stitching/delegateToSchema.ts @@ -11,6 +11,11 @@ import { validate, GraphQLSchema, ExecutionResult, + GraphQLObjectType, + OperationTypeNode, + typeFromAST, + NamedTypeNode, + GraphQLInputType, } from 'graphql'; import { @@ -45,6 +50,20 @@ import { observableToAsyncIterable } from './observableToAsyncIterable'; import { AddMergedTypeFragments } from '../transforms'; import { isAsyncIterable } from 'iterall'; +import { serializeInputValue } from '../utils'; + +function getDelegatingOperation( + parentType: GraphQLObjectType, + schema: GraphQLSchema +): OperationTypeNode { + if (parentType === schema.getMutationType()) { + return 'mutation'; + } else if (parentType === schema.getSubscriptionType()) { + return 'subscription'; + } else { + return 'query'; + } +} export default function delegateToSchema( options: IDelegateToSchemaOptions | GraphQLSchema, @@ -60,14 +79,14 @@ export default function delegateToSchema( schema: subschema, rootValue, info, - operation = info.operation.operation, + operation = getDelegatingOperation(info.parentType, info.schema), fieldName, returnType = info.returnType, args, context, transforms = [], skipValidation, - mergeTypes, + skipTypeMerging, } = options; const request = createDelegatingRequest({ @@ -90,14 +109,14 @@ export default function delegateToSchema( returnType, context, transforms, - mergeTypes, + skipTypeMerging, }); } export function createDelegatingRequest({ schema: subschema, info, - operation = info.operation.operation, + operation = getDelegatingOperation(info.parentType, info.schema), fieldName, args, transforms = [], @@ -132,10 +151,6 @@ export function createDelegatingRequest({ transforms.push( new AddArgumentsAsVariables(targetSchema, args, info.schema) ); - } else { - console.warn( - '"args" undefined. "args" argument may be required in a future version. Custom scalars or enums may not be properly serialized prior to delegation.' - ); } transforms.push( @@ -160,12 +175,12 @@ export function delegateRequest({ schema: subschema, rootValue, info, - operation = info.operation.operation, + operation, fieldName, returnType = info.returnType, context, transforms = [], - mergeTypes, + skipTypeMerging, }: IDelegateRequestOptions): any { let targetSchema: GraphQLSchema; let subschemaConfig: SubschemaConfig; @@ -181,7 +196,7 @@ export function delegateRequest({ } transforms = [ - new CheckResultAndHandleErrors(info, fieldName, subschema, context, returnType, mergeTypes), + new CheckResultAndHandleErrors(info, fieldName, subschema, context, returnType, skipTypeMerging), ...transforms, ]; @@ -261,7 +276,7 @@ function createInitialRequest( selectionSet, name: { kind: Kind.NAME, - value: targetField, + value: targetField || info.fieldNodes[0].name.value, }, }; @@ -272,7 +287,7 @@ function createInitialRequest( const operationDefinition: OperationDefinitionNode = { kind: Kind.OPERATION_DEFINITION, - operation: targetOperation, + operation: targetOperation || getDelegatingOperation(info.parentType, info.schema), variableDefinitions: info.operation.variableDefinitions, selectionSet: rootSelectionSet, name: info.operation.name, @@ -287,9 +302,17 @@ function createInitialRequest( definitions: [operationDefinition, ...fragments], }; + const variableValues = info.variableValues; + const variables = {}; + for (const variableDefinition of info.operation.variableDefinitions) { + const varName = variableDefinition.variable.name.value; + const varType = typeFromAST(info.schema, (variableDefinition.type as NamedTypeNode)) as GraphQLInputType; + variables[varName] = serializeInputValue(varType, variableValues[varName]); + } + return { document, - variables: info.variableValues, + variables, }; } diff --git a/src/stitching/resolvers.ts b/src/stitching/resolvers.ts index 20abeadda63..dae0007cfac 100644 --- a/src/stitching/resolvers.ts +++ b/src/stitching/resolvers.ts @@ -101,12 +101,9 @@ function defaultCreateProxyingResolver( ): GraphQLFieldResolver { return (parent, args, context, info) => delegateToSchema({ schema: subschemaConfig, - operation, fieldName, - args, context, info, - mergeTypes: true, }); } diff --git a/src/test/testAlternateMergeSchemas.ts b/src/test/testAlternateMergeSchemas.ts index 184ce93aa15..03f625cf2be 100644 --- a/src/test/testAlternateMergeSchemas.ts +++ b/src/test/testAlternateMergeSchemas.ts @@ -1760,6 +1760,7 @@ describe('mergeTypes', () => { args: { id: originalResult.id }, context, info, + skipTypeMerging: true, }) } }, @@ -1777,6 +1778,7 @@ describe('mergeTypes', () => { args: { id: originalResult.id }, context, info, + skipTypeMerging: true, }) } }, diff --git a/src/transforms/CheckResultAndHandleErrors.ts b/src/transforms/CheckResultAndHandleErrors.ts index b9c7f71f523..3d8d5b0cdd9 100644 --- a/src/transforms/CheckResultAndHandleErrors.ts +++ b/src/transforms/CheckResultAndHandleErrors.ts @@ -9,7 +9,7 @@ export default class CheckResultAndHandleErrors implements Transform { private fieldName?: string; private subschema?: GraphQLSchema | SubschemaConfig; private returnType?: GraphQLOutputType; - private mergeTypes?: boolean; + private typeMerge?: boolean; constructor( info: IGraphQLToolsResolveInfo, @@ -17,14 +17,14 @@ export default class CheckResultAndHandleErrors implements Transform { subschema?: GraphQLSchema | SubschemaConfig, context?: Record, returnType: GraphQLOutputType = info.returnType, - mergeTypes?: boolean, + typeMerge?: boolean, ) { this.context = context; this.info = info; this.fieldName = fieldName; this.subschema = subschema; this.returnType = returnType; - this.mergeTypes = mergeTypes; + this.typeMerge = typeMerge; } public transformResult(result: any): any { @@ -35,7 +35,7 @@ export default class CheckResultAndHandleErrors implements Transform { this.fieldName, this.subschema, this.returnType, - this.mergeTypes, + this.typeMerge, ); } }