diff --git a/README.md b/README.md index 174d635c..d9af32d2 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,9 @@ The `graphqlHTTP` function accepts the following options: * **`validationRules`**: Optional additional validation rules queries must satisfy in addition to those defined by the GraphQL spec. + * **`execute`**: function which will be used to execute query instead of default + `execute` from `graphql-js`. + In addition to an object defining each option, options can also be provided as a function (or async function) which returns this options object. This function is provided the arguments `(request, response, graphQLParams)` and is called diff --git a/src/__tests__/http-test.js b/src/__tests__/http-test.js index d32acb93..a07d9580 100644 --- a/src/__tests__/http-test.js +++ b/src/__tests__/http-test.js @@ -31,6 +31,7 @@ import { GraphQLString, GraphQLError, BREAK, + execute, } from 'graphql'; import graphqlHTTP from '../'; @@ -1803,6 +1804,37 @@ describe('test harness', () => { }); }); + describe('Custom execute', () => { + it('allow to replace default execute.', async () => { + const app = server(); + + let seenExecuteArgs; + + get( + app, + urlString(), + graphqlHTTP(() => { + return { + schema: TestSchema, + async execute(args) { + seenExecuteArgs = args; + const result = await execute(args); + result.data.test2 = 'Modification'; + return result; + }, + }; + }), + ); + + const response = await request(app).get(urlString({ query: '{test}' })); + + expect(response.text).to.equal( + '{"data":{"test":"Hello World","test2":"Modification"}}', + ); + expect(seenExecuteArgs).to.not.equal(null); + }); + }); + describe('Custom result extensions', () => { it('allows for adding extensions', async () => { const app = server(); diff --git a/src/index.js b/src/index.js index 0ac3a0e5..f952f030 100644 --- a/src/index.js +++ b/src/index.js @@ -18,6 +18,7 @@ import { getOperationAST, specifiedRules, } from 'graphql'; +import type { ExecutionArgs, ExecutionResult } from 'graphql'; import httpError from 'http-errors'; import url from 'url'; @@ -42,6 +43,7 @@ export type Options = ) => OptionsResult) | OptionsResult; export type OptionsResult = OptionsData | Promise; + export type OptionsData = { /** * A GraphQL schema from graphql-js. @@ -92,6 +94,12 @@ export type OptionsData = { * A boolean to optionally enable GraphiQL mode. */ graphiql?: ?boolean, + + /** + * An optional function which will be used to execute query instead of default + * "execute" from graphql-js. + */ + execute?: ?(args: ExecutionArgs) => Promise, }; /** @@ -176,6 +184,7 @@ function graphqlHTTP(options: Options): Middleware { const context = optionsData.context || request; const rootValue = optionsData.rootValue; const graphiql = optionsData.graphiql; + const executeFn = optionsData.execute || execute; pretty = optionsData.pretty; formatErrorFn = optionsData.formatError; extensionsFn = optionsData.extensions; @@ -249,14 +258,14 @@ function graphqlHTTP(options: Options): Middleware { } // Perform the execution, reporting any errors creating the context. try { - return execute( + return executeFn({ schema, - documentAST, + document: documentAST, rootValue, - context, - variables, + contextValue: context, + variableValues: variables, operationName, - ); + }); } catch (contextError) { // Return 400: Bad Request if any execution context errors exist. response.statusCode = 400;