diff --git a/README.md b/README.md index eb9c7f6b..951ee292 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,11 @@ The `graphqlHTTP` function accepts the following options: * **`pretty`**: If `true`, any JSON response will be pretty-printed. + * **`formatError`**: 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. *To enable stack traces, provide the function: `error => error`.* + * **`graphiql`**: If `true`, may present [GraphiQL][] when loaded directly from a browser (a useful tool for debugging and exploration). @@ -124,6 +129,7 @@ new GraphQLObjectType({ ``` [`graphql-js`]: https://github.com/graphql/graphql-js +[`formatError`]: https://github.com/graphql/graphql-js/blob/master/src/error/formatError.js [GraphiQL]: https://github.com/graphql/graphiql [`multer`]: https://github.com/expressjs/multer [`express-session`]: https://github.com/expressjs/session diff --git a/src/__tests__/http-test.js b/src/__tests__/http-test.js index 568fe69f..e08ba2ea 100644 --- a/src/__tests__/http-test.js +++ b/src/__tests__/http-test.js @@ -797,8 +797,7 @@ describe('test harness', () => { var app = express(); app.use(urlString(), graphqlHTTP({ - schema: TestSchema, - pretty: true + schema: TestSchema })); var response = await request(app) @@ -816,12 +815,65 @@ describe('test harness', () => { }); }); + it('allows for custom error formatting to sanitize', async () => { + var app = express(); + + app.use(urlString(), graphqlHTTP({ + schema: TestSchema, + formatError(error) { + return { message: 'Custom error format: ' + error.message }; + } + })); + + var response = await request(app) + .get(urlString({ + query: '{thrower}', + })); + + expect(response.status).to.equal(200); + expect(JSON.parse(response.text)).to.deep.equal({ + data: null, + errors: [ { + message: 'Custom error format: Throws!', + } ] + }); + }); + + it('allows for custom error formatting to elaborate', async () => { + var app = express(); + + app.use(urlString(), graphqlHTTP({ + schema: TestSchema, + formatError(error) { + return { + message: error.message, + locations: error.locations, + stack: 'Stack trace' + }; + } + })); + + var response = await request(app) + .get(urlString({ + query: '{thrower}', + })); + + expect(response.status).to.equal(200); + expect(JSON.parse(response.text)).to.deep.equal({ + data: null, + errors: [ { + message: 'Throws!', + locations: [ { line: 1, column: 2 } ], + stack: 'Stack trace', + } ] + }); + }); + it('handles syntax errors caught by GraphQL', async () => { var app = express(); app.use(urlString(), graphqlHTTP({ schema: TestSchema, - pretty: true })); var error = await catchError( @@ -846,7 +898,6 @@ describe('test harness', () => { app.use(urlString(), graphqlHTTP({ schema: TestSchema, - pretty: true })); var error = await catchError( @@ -864,7 +915,6 @@ describe('test harness', () => { app.use(urlString(), graphqlHTTP({ schema: TestSchema, - pretty: true })); var error = await catchError( @@ -885,7 +935,6 @@ describe('test harness', () => { app.use(urlString(), graphqlHTTP({ schema: TestSchema, - pretty: true })); var error = await catchError( diff --git a/src/index.js b/src/index.js index 7e390b1c..21beec1d 100644 --- a/src/index.js +++ b/src/index.js @@ -46,7 +46,14 @@ export type OptionsObj = { pretty?: ?boolean, /** - * A boolean to optionally enable GraphiQL mode + * 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. + */ + formatError?: ?Function, + + /** + * A boolean to optionally enable GraphiQL mode. */ graphiql?: ?boolean, }; @@ -69,6 +76,7 @@ export default function graphqlHTTP(options: Options): Middleware { let rootValue; let pretty; let graphiql; + let formatErrorFn; let showGraphiQL; let query; let variables; @@ -84,6 +92,7 @@ export default function graphqlHTTP(options: Options): Middleware { rootValue = optionsObj.rootValue; pretty = optionsObj.pretty; graphiql = optionsObj.graphiql; + formatErrorFn = optionsObj.formatError; // GraphQL HTTP only supports GET and POST methods. if (request.method !== 'GET' && request.method !== 'POST') { @@ -177,7 +186,7 @@ export default function graphqlHTTP(options: Options): Middleware { }).then(result => { // Format any encountered errors. if (result && result.errors) { - result.errors = result.errors.map(formatError); + result.errors = result.errors.map(formatErrorFn || formatError); } // If allowed to show GraphiQL, present it instead of JSON.