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

Commit

Permalink
Parse request params before options
Browse files Browse the repository at this point in the history
This ensures that the `request` parameter to the `options()` function is already endowed with metadata about the GraphQL request so that it may be used when constructing options.

Adds a third argument to the function for easier access to graphql specific data.

Addresses #253
  • Loading branch information
leebyron committed May 15, 2017
1 parent d16d9c5 commit 0f0f3e7
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 18 deletions.
15 changes: 15 additions & 0 deletions README.md
Expand Up @@ -63,6 +63,21 @@ The `graphqlHTTP` function accepts the following options:
* **`validationRules`**: Optional additional validation rules queries must
satisfy in addition to those defined by the GraphQL spec.

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
after the request has been parsed.

The `graphQLParams` is provided as the object `{ query, variables, operationName, raw }`.

```js
app.use('/graphql', graphqlHTTP(async (request, response, graphQLParams) => ({
schema: MyGraphQLSchema,
rootValue: await someFunctionToGetRootValue(request)
graphiql: true
})));
```


## HTTP Usage

Expand Down
33 changes: 33 additions & 0 deletions src/__tests__/http-test.js
Expand Up @@ -363,6 +363,39 @@ describe('test harness', () => {
);
});

it('Provides an options function with arguments', async () => {
const app = server();

let seenRequest;
let seenResponse;
let seenParams;

app.use(urlString(), graphqlHTTP((req, res, params) => {
seenRequest = req;
seenResponse = res;
seenParams = params;
return { schema: TestSchema };
}));

const response = await request(app)
.get(urlString({
query: '{test}'
}));

expect(response.text).to.equal(
'{"data":{"test":"Hello World"}}'
);

expect(seenRequest).to.not.equal(null);
expect(seenResponse).to.not.equal(null);
expect(seenParams).to.deep.equal({
query: '{test}',
operationName: null,
variables: null,
raw: false
});
});

it('Catches errors thrown from options function', async () => {
const app = server();

Expand Down
32 changes: 14 additions & 18 deletions src/index.js
Expand Up @@ -134,30 +134,29 @@ function graphqlHTTP(options: Options): Middleware {
return (request: $Request, response: $Response) => {
// Higher scoped variables are referred to at various stages in the
// asynchronous state machine below.
let schema;
let context;
let rootValue;
let params;
let pretty;
let graphiql;
let formatErrorFn;
let extensionsFn;
let showGraphiQL;
let query;

let documentAST;
let variables;
let operationName;
let validationRules;

// Promises are used as a mechanism for capturing any thrown errors during
// the asynchronous process below.

// Resolve the Options to get OptionsData.
return new Promise(resolve => {
resolve(
// Parse the Request to get GraphQL request parameters.
return getGraphQLParams(request).then(graphQLParams => {
params = graphQLParams;
// Then, resolve the Options to get OptionsData.
return new Promise(resolve => resolve(
typeof options === 'function' ?
options(request, response) :
options(request, response, params) :
options
);
));
}).then(optionsData => {
// Assert that optionsData is in fact an Object.
if (!optionsData || typeof optionsData !== 'object') {
Expand All @@ -175,15 +174,15 @@ function graphqlHTTP(options: Options): Middleware {
}

// Collect information from the options data object.
schema = optionsData.schema;
context = optionsData.context || request;
rootValue = optionsData.rootValue;
const schema = optionsData.schema;
const context = optionsData.context || request;
const rootValue = optionsData.rootValue;
const graphiql = optionsData.graphiql;
pretty = optionsData.pretty;
graphiql = optionsData.graphiql;
formatErrorFn = optionsData.formatError;
extensionsFn = optionsData.extensions;

validationRules = specifiedRules;
let validationRules = specifiedRules;
if (optionsData.validationRules) {
validationRules = validationRules.concat(optionsData.validationRules);
}
Expand All @@ -194,9 +193,6 @@ function graphqlHTTP(options: Options): Middleware {
throw httpError(405, 'GraphQL only supports GET and POST requests.');
}

// Parse the Request to get GraphQL request parameters.
return getGraphQLParams(request);
}).then(params => {
// Get GraphQL params from the request and POST body data.
query = params.query;
variables = params.variables;
Expand Down

0 comments on commit 0f0f3e7

Please sign in to comment.