From 2acf5654c377173baf11670561f279bb15dd10ec Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 2 Apr 2018 22:49:43 -0300 Subject: [PATCH] Added an option to support additional extensions (Originally #934, tweaked by @glasser.) --- docs/source/setup.md | 9 ++-- .../apollo-server-core/src/graphqlOptions.ts | 2 + .../apollo-server-core/src/runHttpQuery.ts | 1 + .../apollo-server-core/src/runQuery.test.ts | 48 +++++++++++++++++++ packages/apollo-server-core/src/runQuery.ts | 3 +- 5 files changed, 59 insertions(+), 4 deletions(-) diff --git a/docs/source/setup.md b/docs/source/setup.md index f95e3659..23a5a2b1 100644 --- a/docs/source/setup.md +++ b/docs/source/setup.md @@ -107,13 +107,16 @@ const GraphQLOptions = { validationRules?: Array, // a function applied to each graphQL execution result - formatResponse?: Function + formatResponse?: Function, // a custom default field resolver - fieldResolver?: Function + fieldResolver?: Function, // a boolean that will print additional debug logging if execution errors occur - debug?: boolean + debug?: boolean, + + // (optional) extra GraphQL extensions from graphql-extensions + extensions?: Array } ``` diff --git a/packages/apollo-server-core/src/graphqlOptions.ts b/packages/apollo-server-core/src/graphqlOptions.ts index 5c251652..23561a68 100644 --- a/packages/apollo-server-core/src/graphqlOptions.ts +++ b/packages/apollo-server-core/src/graphqlOptions.ts @@ -19,6 +19,7 @@ import { GraphQLExtension } from 'graphql-extensions'; * - (optional) formatResponse: a function applied to each graphQL execution result * - (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 GraphQLExtension * */ export interface GraphQLServerOptions< @@ -39,6 +40,7 @@ export interface GraphQLServerOptions< tracing?: boolean; // cacheControl?: boolean | CacheControlExtensionOptions; cacheControl?: boolean | any; + extensions?: Array; } export default GraphQLServerOptions; diff --git a/packages/apollo-server-core/src/runHttpQuery.ts b/packages/apollo-server-core/src/runHttpQuery.ts index 34e34ed2..dbe287d3 100644 --- a/packages/apollo-server-core/src/runHttpQuery.ts +++ b/packages/apollo-server-core/src/runHttpQuery.ts @@ -255,6 +255,7 @@ export async function runHttpQuery( tracing: optionsObject.tracing, cacheControl: optionsObject.cacheControl, request: request.request, + extensions: optionsObject.extensions, }; if (optionsObject.formatParams) { diff --git a/packages/apollo-server-core/src/runQuery.test.ts b/packages/apollo-server-core/src/runQuery.test.ts index bc52add9..b60e5192 100644 --- a/packages/apollo-server-core/src/runQuery.test.ts +++ b/packages/apollo-server-core/src/runQuery.test.ts @@ -20,6 +20,7 @@ import { LogAction, LogStep } from './logging'; // environment. import { makeCompatible } from 'meteor-promise'; import Fiber = require('fibers'); +import { GraphQLExtensionStack, GraphQLExtension } from 'graphql-extensions'; makeCompatible(Promise, Fiber); const queryType = new GraphQLObjectType({ @@ -366,6 +367,53 @@ describe('runQuery', () => { }); }); + describe('graphql extensions', () => { + class CustomExtension implements GraphQLExtension { + format(): [string, any] { + return ['customExtension', { foo: 'bar' }]; + } + } + + it('creates the extension stack', async () => { + const query = `{ testString }`; + const expected = { testString: 'it works' }; + const extensions = [CustomExtension]; + return runQuery({ + schema: new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'QueryType', + fields: { + testString: { + type: GraphQLString, + resolve(root, args, context) { + expect(context._extensionStack).to.be.instanceof( + GraphQLExtensionStack, + ); + expect( + context._extensionStack.extensions[0], + ).to.be.instanceof(CustomExtension); + }, + }, + }, + }), + }), + query, + extensions, + }); + }); + + it('runs format response from extensions', async () => { + const query = `{ testString }`; + const expected = { testString: 'it works' }; + const extensions = [CustomExtension]; + return runQuery({ schema, query: query, extensions }).then(res => { + return expect(res.extensions).to.deep.equal({ + customExtension: { foo: 'bar' }, + }); + }); + }); + }); + describe('async_hooks', () => { let asyncHooks; let asyncHook; diff --git a/packages/apollo-server-core/src/runQuery.ts b/packages/apollo-server-core/src/runQuery.ts index 682e0cd6..c2a383d7 100644 --- a/packages/apollo-server-core/src/runQuery.ts +++ b/packages/apollo-server-core/src/runQuery.ts @@ -64,6 +64,7 @@ export interface QueryOptions { // cacheControl?: boolean | CacheControlExtensionOptions; cacheControl?: boolean | any; request: Request; + extensions?: Array; } function isQueryOperation(query: DocumentNode, operationName: string) { @@ -98,7 +99,7 @@ function doRunQuery(options: QueryOptions): Promise { logFunction({ action: LogAction.request, step: LogStep.start }); const context = options.context || {}; - let extensions = []; + let extensions = options.extensions !== undefined ? options.extensions : []; if (options.tracing) { extensions.push(TracingExtension); }