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

Commit 898a033

Browse files
jamesmoriartyIvanGoncharov
authored andcommitted
Add support for customValidateFn and rename formatError to customFormatErrorFn
* formatError is deprecated. * customFormatErrorFn to replace formatError.
1 parent 3c864bc commit 898a033

File tree

3 files changed

+156
-21
lines changed

3 files changed

+156
-21
lines changed

README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,6 @@ The `graphqlHTTP` function accepts the following options:
7777

7878
* **`pretty`**: If `true`, any JSON response will be pretty-printed.
7979

80-
* **`formatError`**: An optional function which will be used to format any
81-
errors produced by fulfilling a GraphQL operation. If no function is
82-
provided, GraphQL's default spec-compliant [`formatError`][] function will be used.
83-
8480
* **`extensions`**: An optional function for adding additional metadata to the
8581
GraphQL response as a key-value object. The result will be added to
8682
`"extensions"` field in the resulting JSON. This is often a useful place to
@@ -91,6 +87,16 @@ The `graphqlHTTP` function accepts the following options:
9187
* **`validationRules`**: Optional additional validation rules queries must
9288
satisfy in addition to those defined by the GraphQL spec.
9389

90+
* **`customValidateFn`**: An optional function which will be used to validate
91+
instead of default `validate` from `graphql-js`.
92+
93+
* **`customFormatErrorFn`**: An optional function which will be used to format any
94+
errors produced by fulfilling a GraphQL operation. If no function is
95+
provided, GraphQL's default spec-compliant [`formatError`][] function will be used.
96+
97+
* **`formatError`**: is deprecated and replaced by `customFormatErrorFn`. It will be
98+
removed in version 1.0.0.
99+
94100
In addition to an object defining each option, options can also be provided as
95101
a function (or async function) which returns this options object. This function
96102
is provided the arguments `(request, response, graphQLParams)` and is called
@@ -288,10 +294,10 @@ graphqlHTTP.getGraphQLParams(request).then(params => {
288294
## Debugging Tips
289295

290296
During development, it's useful to get more information from errors, such as
291-
stack traces. Providing a function to `formatError` enables this:
297+
stack traces. Providing a function to `customFormatErrorFn` enables this:
292298

293299
```js
294-
formatError: error => ({
300+
customFormatErrorFn: error => ({
295301
message: error.message,
296302
locations: error.locations,
297303
stack: error.stack ? error.stack.split('\n') : [],

src/__tests__/http-test.js

Lines changed: 103 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
GraphQLString,
2929
GraphQLError,
3030
BREAK,
31+
validate,
3132
} from 'graphql';
3233
import graphqlHTTP from '../';
3334

@@ -1205,7 +1206,7 @@ describe('test harness', () => {
12051206
urlString(),
12061207
graphqlHTTP({
12071208
schema: TestSchema,
1208-
formatError(error) {
1209+
customFormatErrorFn(error) {
12091210
return { message: 'Custom error format: ' + error.message };
12101211
},
12111212
}),
@@ -1236,7 +1237,7 @@ describe('test harness', () => {
12361237
urlString(),
12371238
graphqlHTTP({
12381239
schema: TestSchema,
1239-
formatError(error) {
1240+
customFormatErrorFn(error) {
12401241
return {
12411242
message: error.message,
12421243
locations: error.locations,
@@ -1466,7 +1467,7 @@ describe('test harness', () => {
14661467
});
14671468
});
14681469

1469-
it('allows for custom error formatting of poorly formed requests', async () => {
1470+
it('`formatError` is deprecated', async () => {
14701471
const app = server();
14711472

14721473
get(
@@ -1480,6 +1481,46 @@ describe('test harness', () => {
14801481
}),
14811482
);
14821483

1484+
const spy = sinon.spy(console, 'warn');
1485+
1486+
const response = await request(app).get(
1487+
urlString({
1488+
variables: 'who:You',
1489+
query: 'query helloWho($who: String){ test(who: $who) }',
1490+
}),
1491+
);
1492+
1493+
expect(
1494+
spy.calledWith(
1495+
'`formatError` is deprecated and replaced by `customFormatErrorFn`. It will be removed in version 1.0.0.',
1496+
),
1497+
);
1498+
expect(response.status).to.equal(400);
1499+
expect(JSON.parse(response.text)).to.deep.equal({
1500+
errors: [
1501+
{
1502+
message: 'Custom error format: Variables are invalid JSON.',
1503+
},
1504+
],
1505+
});
1506+
1507+
spy.restore();
1508+
});
1509+
1510+
it('allows for custom error formatting of poorly formed requests', async () => {
1511+
const app = server();
1512+
1513+
get(
1514+
app,
1515+
urlString(),
1516+
graphqlHTTP({
1517+
schema: TestSchema,
1518+
customFormatErrorFn(error) {
1519+
return { message: 'Custom error format: ' + error.message };
1520+
},
1521+
}),
1522+
);
1523+
14831524
const response = await request(app).get(
14841525
urlString({
14851526
variables: 'who:You',
@@ -1859,6 +1900,64 @@ describe('test harness', () => {
18591900
});
18601901
});
18611902

1903+
describe('Custom validate function', () => {
1904+
it('returns data', async () => {
1905+
const app = server();
1906+
1907+
get(
1908+
app,
1909+
urlString(),
1910+
graphqlHTTP({
1911+
schema: TestSchema,
1912+
customValidateFn(schema, documentAST, validationRules) {
1913+
return validate(schema, documentAST, validationRules);
1914+
},
1915+
}),
1916+
);
1917+
1918+
const response = await request(app)
1919+
.get(urlString({ query: '{test}', raw: '' }))
1920+
.set('Accept', 'text/html');
1921+
1922+
expect(response.status).to.equal(200);
1923+
expect(response.text).to.equal('{"data":{"test":"Hello World"}}');
1924+
});
1925+
1926+
it('returns validation errors', async () => {
1927+
const app = server();
1928+
1929+
get(
1930+
app,
1931+
urlString(),
1932+
graphqlHTTP({
1933+
schema: TestSchema,
1934+
customValidateFn(schema, documentAST, validationRules) {
1935+
const errors = validate(schema, documentAST, validationRules);
1936+
1937+
const error = new GraphQLError(`custom error ${errors.length}`);
1938+
1939+
return [error];
1940+
},
1941+
}),
1942+
);
1943+
1944+
const response = await request(app).get(
1945+
urlString({
1946+
query: '{thrower}',
1947+
}),
1948+
);
1949+
1950+
expect(response.status).to.equal(400);
1951+
expect(JSON.parse(response.text)).to.deep.equal({
1952+
errors: [
1953+
{
1954+
message: 'custom error 0',
1955+
},
1956+
],
1957+
});
1958+
});
1959+
});
1960+
18621961
describe('Custom validation rules', () => {
18631962
const AlwaysInvalidRule = function(context) {
18641963
return {
@@ -1946,7 +2045,7 @@ describe('test harness', () => {
19462045
urlString(),
19472046
graphqlHTTP({
19482047
schema: TestSchema,
1949-
formatError: () => null,
2048+
customFormatErrorFn: () => null,
19502049
extensions({ result }) {
19512050
return { preservedErrors: (result: any).errors };
19522051
},

src/index.js

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -72,18 +72,34 @@ export type OptionsData = {
7272
*/
7373
pretty?: ?boolean,
7474

75+
/**
76+
* An optional array of validation rules that will be applied on the document
77+
* in additional to those defined by the GraphQL spec.
78+
*/
79+
validationRules?: ?Array<(ValidationContext) => ASTVisitor>,
80+
81+
/**
82+
* An optional function which will be used to validate instead of default `validate`
83+
* from `graphql-js`.
84+
*/
85+
customValidateFn?: ?(
86+
schema: GraphQLSchema,
87+
documentAST: DocumentNode,
88+
rules: $ReadOnlyArray<any>,
89+
) => $ReadOnlyArray<GraphQLError>,
90+
7591
/**
7692
* An optional function which will be used to format any errors produced by
7793
* fulfilling a GraphQL operation. If no function is provided, GraphQL's
7894
* default spec-compliant `formatError` function will be used.
7995
*/
80-
formatError?: ?(error: GraphQLError) => mixed,
96+
customFormatErrorFn?: ?(error: GraphQLError) => mixed,
8197

8298
/**
83-
* An optional array of validation rules that will be applied on the document
84-
* in additional to those defined by the GraphQL spec.
99+
* `formatError` is deprecated and replaced by `customFormatErrorFn`. It will
100+
* be removed in version 1.0.0.
85101
*/
86-
validationRules?: ?Array<(ValidationContext) => ASTVisitor>,
102+
formatError?: ?(error: GraphQLError) => mixed,
87103

88104
/**
89105
* An optional function for adding additional metadata to the GraphQL response
@@ -158,7 +174,8 @@ function graphqlHTTP(options: Options): Middleware {
158174
let context;
159175
let params;
160176
let pretty;
161-
let formatErrorFn;
177+
let formatErrorFn = formatError;
178+
let validateFn = validate;
162179
let extensionsFn;
163180
let showGraphiQL;
164181
let query;
@@ -201,7 +218,6 @@ function graphqlHTTP(options: Options): Middleware {
201218
const rootValue = optionsData.rootValue;
202219
const fieldResolver = optionsData.fieldResolver;
203220
const graphiql = optionsData.graphiql;
204-
205221
context = optionsData.context || request;
206222

207223
let validationRules = specifiedRules;
@@ -251,7 +267,12 @@ function graphqlHTTP(options: Options): Middleware {
251267
}
252268

253269
// Validate AST, reporting any errors.
254-
const validationErrors = validate(schema, documentAST, validationRules);
270+
const validationErrors = validateFn(
271+
schema,
272+
documentAST,
273+
validationRules,
274+
);
275+
255276
if (validationErrors.length > 0) {
256277
// Return 400: Bad Request if any validation errors exist.
257278
response.statusCode = 400;
@@ -333,9 +354,7 @@ function graphqlHTTP(options: Options): Middleware {
333354
}
334355
// Format any encountered errors.
335356
if (result && result.errors) {
336-
(result: any).errors = result.errors.map(
337-
formatErrorFn || formatError,
338-
);
357+
(result: any).errors = result.errors.map(formatErrorFn);
339358
}
340359

341360
// If allowed to show GraphiQL, present it instead of JSON.
@@ -380,7 +399,18 @@ function graphqlHTTP(options: Options): Middleware {
380399
);
381400
}
382401

383-
formatErrorFn = optionsData.formatError;
402+
if (optionsData.formatError) {
403+
// eslint-disable-next-line no-console
404+
console.warn(
405+
'`formatError` is deprecated and replaced by `customFormatErrorFn`. It will be removed in version 1.0.0.',
406+
);
407+
}
408+
409+
validateFn = optionsData.customValidateFn || validateFn;
410+
formatErrorFn =
411+
optionsData.customFormatErrorFn ||
412+
optionsData.formatError ||
413+
formatErrorFn;
384414
extensionsFn = optionsData.extensions;
385415
pretty = optionsData.pretty;
386416
return optionsData;

0 commit comments

Comments
 (0)