diff --git a/src/stitching/makeRemoteExecutableSchema.ts b/src/stitching/makeRemoteExecutableSchema.ts index 17844912f46..745832a8c43 100644 --- a/src/stitching/makeRemoteExecutableSchema.ts +++ b/src/stitching/makeRemoteExecutableSchema.ts @@ -19,7 +19,8 @@ import { printSchema, Kind, GraphQLResolveInfo, - DocumentNode + DocumentNode, + BuildSchemaOptions } from 'graphql'; import linkToFetcher, { execute } from './linkToFetcher'; import isEmptyObject from '../isEmptyObject'; @@ -30,12 +31,13 @@ import resolveParentFromTypename from './resolveFromParentTypename'; import defaultMergedResolver from './defaultMergedResolver'; import { checkResultAndHandleErrors } from './errors'; import { observableToAsyncIterable } from './observableToAsyncIterable'; +import { Options as PrintSchemaOptions } from 'graphql/utilities/schemaPrinter'; export type ResolverFn = ( rootValue?: any, args?: any, context?: any, - info?: GraphQLResolveInfo, + info?: GraphQLResolveInfo ) => AsyncIterator; export type Fetcher = (operation: FetcherOperation) => Promise; @@ -51,26 +53,28 @@ export default function makeRemoteExecutableSchema({ schema, link, fetcher, - createResolver: customCreateResolver = createResolver + createResolver: customCreateResolver = createResolver, + buildSchemaOptions, + printSchemaOptions = { commentDescriptions: true } }: { schema: GraphQLSchema | string; link?: ApolloLink; fetcher?: Fetcher; - createResolver?: (fetcher: Fetcher) => GraphQLFieldResolver + createResolver?: (fetcher: Fetcher) => GraphQLFieldResolver; + buildSchemaOptions?: BuildSchemaOptions; + printSchemaOptions?: PrintSchemaOptions; }): GraphQLSchema { if (!fetcher && link) { fetcher = linkToFetcher(link); } let typeDefs: string; - const printOptions = { commentDescriptions: true }; if (typeof schema === 'string') { typeDefs = schema; - schema = buildSchema(typeDefs); + schema = buildSchema(typeDefs, buildSchemaOptions); } else { - // TODO fix types https://github.com/apollographql/graphql-tools/issues/542 - typeDefs = (printSchema as any)(schema, printOptions); + typeDefs = printSchema(schema, printSchemaOptions); } // prepare query resolvers @@ -98,7 +102,7 @@ export default function makeRemoteExecutableSchema({ const subscriptions = subscriptionType.getFields(); Object.keys(subscriptions).forEach(key => { subscriptionResolvers[key] = { - subscribe: createSubscriptionResolver(key, link), + subscribe: createSubscriptionResolver(key, link) }; }); } @@ -118,14 +122,11 @@ export default function makeRemoteExecutableSchema({ const typeMap = schema.getTypeMap(); const types = Object.keys(typeMap).map(name => typeMap[name]); for (const type of types) { - if ( - type instanceof GraphQLInterfaceType || - type instanceof GraphQLUnionType - ) { + if (type instanceof GraphQLInterfaceType || type instanceof GraphQLUnionType) { resolvers[type.name] = { __resolveType(parent, context, info) { return resolveParentFromTypename(parent, info.schema); - }, + } }; } else if (type instanceof GraphQLScalarType) { if ( @@ -137,11 +138,7 @@ export default function makeRemoteExecutableSchema({ type === GraphQLInt ) ) { - resolvers[type.name] = recreateType( - type, - (name: string) => null, - false, - ) as GraphQLScalarType; + resolvers[type.name] = recreateType(type, (name: string) => null, false) as GraphQLScalarType; } } else if ( type instanceof GraphQLObjectType && @@ -160,45 +157,38 @@ export default function makeRemoteExecutableSchema({ return makeExecutableSchema({ typeDefs, - resolvers, + resolvers }); } export function createResolver(fetcher: Fetcher): GraphQLFieldResolver { return async (root, args, context, info) => { - const fragments = Object.keys(info.fragments).map( - fragment => info.fragments[fragment], - ); + const fragments = Object.keys(info.fragments).map(fragment => info.fragments[fragment]); const document = { kind: Kind.DOCUMENT, - definitions: [info.operation, ...fragments], + definitions: [info.operation, ...fragments] }; const result = await fetcher({ query: document, variables: info.variableValues, - context: { graphqlContext: context }, + context: { graphqlContext: context } }); return checkResultAndHandleErrors(result, info); }; } -function createSubscriptionResolver( - name: string, - link: ApolloLink, -): ResolverFn { +function createSubscriptionResolver(name: string, link: ApolloLink): ResolverFn { return (root, args, context, info) => { - const fragments = Object.keys(info.fragments).map( - fragment => info.fragments[fragment], - ); + const fragments = Object.keys(info.fragments).map(fragment => info.fragments[fragment]); const document = { kind: Kind.DOCUMENT, - definitions: [info.operation, ...fragments], + definitions: [info.operation, ...fragments] }; const operation = { query: document, variables: info.variableValues, - context: { graphqlContext: context }, + context: { graphqlContext: context } }; const observable = execute(link, operation); diff --git a/src/test/testMakeRemoteExecutableSchema.ts b/src/test/testMakeRemoteExecutableSchema.ts index 3ad4cf3cc2c..42b73c5f483 100644 --- a/src/test/testMakeRemoteExecutableSchema.ts +++ b/src/test/testMakeRemoteExecutableSchema.ts @@ -7,8 +7,9 @@ import { subscriptionSchema, subscriptionPubSubTrigger, subscriptionPubSub, - makeSchemaRemoteFromLink, + makeSchemaRemoteFromLink } from '../test/testingSchemas'; +import { makeRemoteExecutableSchema } from '../stitching'; describe('remote subscriptions', () => { let schema: GraphQLSchema; @@ -19,8 +20,8 @@ describe('remote subscriptions', () => { it('should work', done => { const mockNotification = { notifications: { - text: 'Hello world', - }, + text: 'Hello world' + } }; const subscription = parse(` @@ -37,7 +38,7 @@ describe('remote subscriptions', () => { expect(result).to.have.property('data'); expect(result.data).to.deep.equal(mockNotification); !notificationCnt++ ? done() : null; - }), + }) ); subscriptionPubSub.publish(subscriptionPubSubTrigger, mockNotification); @@ -46,8 +47,8 @@ describe('remote subscriptions', () => { it('should work without triggering multiple times per notification', done => { const mockNotification = { notifications: { - text: 'Hello world', - }, + text: 'Hello world' + } }; const subscription = parse(` @@ -64,14 +65,14 @@ describe('remote subscriptions', () => { expect(result).to.have.property('data'); expect(result.data).to.deep.equal(mockNotification); notificationCnt++; - }), + }) ); subscribe(schema, subscription).then(results => forAwaitEach(results as AsyncIterable, (result: ExecutionResult) => { expect(result).to.have.property('data'); expect(result.data).to.deep.equal(mockNotification); - }), + }) ); subscriptionPubSub.publish(subscriptionPubSubTrigger, mockNotification); @@ -83,3 +84,34 @@ describe('remote subscriptions', () => { }, 0); }); }); + +describe('respects buildSchema options', () => { + const schema = ` + type Query { + # Field description + custom: CustomScalar! + } + + # Scalar description + scalar CustomScalar +`; + + it('without comment descriptions', () => { + const remoteSchema = makeRemoteExecutableSchema({ schema }); + + const customScalar = remoteSchema.getType('CustomScalar'); + expect(customScalar.description).to.eq(undefined); + }); + + it('with comment descriptions', () => { + const remoteSchema = makeRemoteExecutableSchema({ + schema, + buildSchemaOptions: { commentDescriptions: true } + }); + + const field = remoteSchema.getQueryType().getFields()['custom']; + expect(field.description).to.eq('Field description'); + const customScalar = remoteSchema.getType('CustomScalar'); + expect(customScalar.description).to.eq('Scalar description'); + }); +});