Skip to content
This repository has been archived by the owner on Mar 20, 2023. It is now read-only.

Allow to replace default execute function #391

Merged
merged 1 commit into from Apr 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Expand Up @@ -90,6 +90,9 @@ The `graphqlHTTP` function accepts the following options:
* **`customValidateFn`**: An optional function which will be used to validate
instead of default `validate` from `graphql-js`.

* **`customExecuteFn`**: An optional function which will be used to execute
instead of default `execute` from `graphql-js`.

* **`customFormatErrorFn`**: An optional function which will be used to format any
errors produced by fulfilling a GraphQL operation. If no function is
provided, GraphQL's default spec-compliant [`formatError`][] function will be used.
Expand Down
32 changes: 32 additions & 0 deletions src/__tests__/http-test.js
Expand Up @@ -29,6 +29,7 @@ import {
GraphQLError,
BREAK,
validate,
execute,
} from 'graphql';
import graphqlHTTP from '../';

Expand Down Expand Up @@ -2000,6 +2001,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 customExecuteFn(args) {
seenExecuteArgs = args;
const result: any = await Promise.resolve(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();
Expand Down
20 changes: 15 additions & 5 deletions src/index.js
Expand Up @@ -20,6 +20,7 @@ import {
getOperationAST,
specifiedRules,
} from 'graphql';
import type { ExecutionArgs, ExecutionResult } from 'graphql';
import httpError from 'http-errors';
import url from 'url';

Expand Down Expand Up @@ -51,6 +52,7 @@ export type Options =
) => OptionsResult)
| OptionsResult;
export type OptionsResult = OptionsData | Promise<OptionsData>;

export type OptionsData = {
/**
* A GraphQL schema from graphql-js.
Expand Down Expand Up @@ -88,6 +90,12 @@ export type OptionsData = {
rules: $ReadOnlyArray<any>,
) => $ReadOnlyArray<GraphQLError>,

/**
* An optional function which will be used to execute instead of default `execute`
* from `graphql-js`.
*/
customExecuteFn?: ?(args: ExecutionArgs) => Promise<ExecutionResult>,

/**
* An optional function which will be used to format any errors produced by
* fulfilling a GraphQL operation. If no function is provided, GraphQL's
Expand Down Expand Up @@ -176,6 +184,7 @@ function graphqlHTTP(options: Options): Middleware {
let pretty;
let formatErrorFn = formatError;
let validateFn = validate;
let executeFn = execute;
let extensionsFn;
let showGraphiQL;
let query;
Expand Down Expand Up @@ -302,15 +311,15 @@ 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,
fieldResolver,
);
});
} catch (contextError) {
// Return 400: Bad Request if any execution context errors exist.
response.statusCode = 400;
Expand Down Expand Up @@ -407,6 +416,7 @@ function graphqlHTTP(options: Options): Middleware {
}

validateFn = optionsData.customValidateFn || validateFn;
executeFn = optionsData.customExecuteFn || executeFn;
formatErrorFn =
optionsData.customFormatErrorFn ||
optionsData.formatError ||
Expand Down