diff --git a/packages/apollo-server-core/src/ApolloServer.ts b/packages/apollo-server-core/src/ApolloServer.ts index bfc01a3fdb2..69172d23fea 100644 --- a/packages/apollo-server-core/src/ApolloServer.ts +++ b/packages/apollo-server-core/src/ApolloServer.ts @@ -1,4 +1,8 @@ -import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools'; +import { + makeExecutableSchema, + addMockFunctionsToSchema, + GraphQLParseOptions, +} from 'graphql-tools'; import { Server as HttpServer } from 'http'; import { execute, @@ -123,6 +127,8 @@ export class ApolloServerBase { // on the same operation to be executed immediately. private documentStore?: InMemoryLRUCache; + private parseOptions: GraphQLParseOptions; + // The constructor should be universal across all environments. All environment specific behavior should be set by adding or overriding methods constructor(config: Config) { if (!config) throw new Error('ApolloServer requires options.'); @@ -133,6 +139,7 @@ export class ApolloServerBase { schemaDirectives, modules, typeDefs, + parseOptions = {}, introspection, mocks, mockEntireSchema, @@ -291,9 +298,12 @@ export class ApolloServerBase { typeDefs: augmentedTypeDefs, schemaDirectives, resolvers, + parseOptions, }); } + this.parseOptions = parseOptions; + if (mocks || (typeof mockEntireSchema !== 'undefined' && mocks !== false)) { addMockFunctionsToSchema({ schema: this.schema, @@ -546,6 +556,7 @@ export class ApolloServerBase { any, any >, + parseOptions: this.parseOptions, ...this.requestOptions, } as GraphQLOptions; } diff --git a/packages/apollo-server-core/src/graphqlOptions.ts b/packages/apollo-server-core/src/graphqlOptions.ts index c1e36ffa2c6..3511f29641a 100644 --- a/packages/apollo-server-core/src/graphqlOptions.ts +++ b/packages/apollo-server-core/src/graphqlOptions.ts @@ -9,6 +9,7 @@ import { CacheControlExtensionOptions } from 'apollo-cache-control'; import { KeyValueCache, InMemoryLRUCache } from 'apollo-server-caching'; import { DataSource } from 'apollo-datasource'; import { ApolloServerPlugin } from 'apollo-server-plugin-base'; +import { GraphQLParseOptions } from 'graphql-tools'; /* * GraphQLServerOptions @@ -22,6 +23,7 @@ import { ApolloServerPlugin } from 'apollo-server-plugin-base'; * - (optional) fieldResolver: a custom default field resolver * - (optional) debug: a boolean that will print additional debug logging if execution errors occur * - (optional) extensions: an array of functions which create GraphQLExtensions (each GraphQLExtension object is used for one request) + * - (optional) parseOptions: options to pass when parsing schemas and queries * */ export interface GraphQLServerOptions< @@ -44,6 +46,7 @@ export interface GraphQLServerOptions< persistedQueries?: PersistedQueryOptions; plugins?: ApolloServerPlugin[]; documentStore?: InMemoryLRUCache; + parseOptions?: GraphQLParseOptions; } export type DataSources = { diff --git a/packages/apollo-server-core/src/requestPipeline.ts b/packages/apollo-server-core/src/requestPipeline.ts index e7d39f09126..d2f048b766f 100644 --- a/packages/apollo-server-core/src/requestPipeline.ts +++ b/packages/apollo-server-core/src/requestPipeline.ts @@ -44,6 +44,7 @@ import { import { Dispatcher } from './utils/dispatcher'; import { InMemoryLRUCache, KeyValueCache } from 'apollo-server-caching'; +import { GraphQLParseOptions } from 'graphql-tools'; export { GraphQLRequest, @@ -79,6 +80,8 @@ export interface GraphQLRequestPipelineConfig { plugins?: ApolloServerPlugin[]; documentStore?: InMemoryLRUCache; + + parseOptions?: GraphQLParseOptions; } export type DataSources = { @@ -195,7 +198,7 @@ export async function processGraphQLRequest( ); try { - requestContext.document = parse(query); + requestContext.document = parse(query, config.parseOptions); parsingDidEnd(); } catch (syntaxError) { parsingDidEnd(syntaxError); @@ -307,13 +310,16 @@ export async function processGraphQLRequest( requestDidEnd(); } - function parse(query: string): DocumentNode { + function parse( + query: string, + parseOptions?: GraphQLParseOptions, + ): DocumentNode { const parsingDidEnd = extensionStack.parsingDidStart({ queryString: query, }); try { - return graphql.parse(query); + return graphql.parse(query, parseOptions); } finally { parsingDidEnd(); } diff --git a/packages/apollo-server-core/src/types.ts b/packages/apollo-server-core/src/types.ts index 36d050ad487..88358a7696a 100644 --- a/packages/apollo-server-core/src/types.ts +++ b/packages/apollo-server-core/src/types.ts @@ -1,5 +1,10 @@ import { GraphQLSchema, DocumentNode } from 'graphql'; -import { SchemaDirectiveVisitor, IResolvers, IMocks } from 'graphql-tools'; +import { + SchemaDirectiveVisitor, + IResolvers, + IMocks, + GraphQLParseOptions, +} from 'graphql-tools'; import { ConnectionContext } from 'subscriptions-transport-ws'; import WebSocket from 'ws'; import { GraphQLExtension } from 'graphql-extensions'; @@ -42,23 +47,25 @@ export interface SubscriptionServerOptions { onDisconnect?: (websocket: WebSocket, context: ConnectionContext) => any; } +type BaseConfig = Pick< + GraphQLOptions>, + | 'formatError' + | 'debug' + | 'rootValue' + | 'validationRules' + | 'formatResponse' + | 'fieldResolver' + | 'tracing' + | 'dataSources' + | 'cache' +>; + // This configuration is shared between all integrations and should include // fields that are not specific to a single integration -export interface Config - extends Pick< - GraphQLOptions>, - | 'formatError' - | 'debug' - | 'rootValue' - | 'validationRules' - | 'formatResponse' - | 'fieldResolver' - | 'tracing' - | 'dataSources' - | 'cache' - > { +export interface Config extends BaseConfig { modules?: GraphQLSchemaModule[]; typeDefs?: DocumentNode | Array; + parseOptions?: GraphQLParseOptions; resolvers?: IResolvers; schema?: GraphQLSchema; schemaDirectives?: Record;