diff --git a/src/error/GraphQLError.d.ts b/src/error/GraphQLError.d.ts index 95f39ba483..edf0b4d2a6 100644 --- a/src/error/GraphQLError.d.ts +++ b/src/error/GraphQLError.d.ts @@ -82,6 +82,10 @@ export class GraphQLError extends Error { * Extension fields to add to the formatted error. */ readonly extensions: { [key: string]: any }; + + toString(): string; + + toJSON(): GraphQLFormattedError; } /** @@ -89,3 +93,40 @@ export class GraphQLError extends Error { * about the error's position in the source. */ export function printError(error: GraphQLError): string; + +/** + * Given a GraphQLError, format it according to the rules described by the + * Response Format, Errors section of the GraphQL Specification. + */ +export function formatError(error: GraphQLError): GraphQLFormattedError; + +/** + * @see https://github.com/graphql/graphql-spec/blob/master/spec/Section%207%20--%20Response.md#errors + */ +export interface GraphQLFormattedError< + TExtensions extends Record = Record +> { + /** + * A short, human-readable summary of the problem that **SHOULD NOT** change + * from occurrence to occurrence of the problem, except for purposes of + * localization. + */ + readonly message: string; + /** + * If an error can be associated to a particular point in the requested + * GraphQL document, it should contain a list of locations. + */ + readonly locations?: ReadonlyArray; + /** + * If an error can be associated to a particular field in the GraphQL result, + * it _must_ contain an entry with the key `path` that details the path of + * the response field which experienced the error. This allows clients to + * identify whether a null result is intentional or caused by a runtime error. + */ + readonly path?: ReadonlyArray; + /** + * Reserved for implementors to extend the protocol however they see fit, + * and hence there are no additional restrictions on its contents. + */ + readonly extensions?: TExtensions; +} diff --git a/src/error/GraphQLError.js b/src/error/GraphQLError.js index 7c5e74e73d..daf70d83ba 100644 --- a/src/error/GraphQLError.js +++ b/src/error/GraphQLError.js @@ -7,6 +7,9 @@ import type { SourceLocation } from '../language/location'; import { getLocation } from '../language/location'; import { printLocation, printSourceLocation } from '../language/printLocation'; +import { formatError } from './formatError'; +import type { GraphQLFormattedError } from './formatError'; + /** * A GraphQLError describes an Error found during the parse, validate, or * execute phases of performing a GraphQL operation. In addition to a message @@ -157,6 +160,10 @@ export class GraphQLError extends Error { return printError(this); } + toJSON(): GraphQLFormattedError { + return formatError(this); + } + // FIXME: workaround to not break chai comparisons, should be remove in v16 // $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet get [SYMBOL_TO_STRING_TAG](): string { diff --git a/src/error/__tests__/GraphQLError-test.js b/src/error/__tests__/GraphQLError-test.js index ef1964fc82..508cce7d2b 100644 --- a/src/error/__tests__/GraphQLError-test.js +++ b/src/error/__tests__/GraphQLError-test.js @@ -293,3 +293,52 @@ describe('printError', () => { `); }); }); + +describe('toJSON', () => { + it('includes path', () => { + const error = new GraphQLError('msg', null, null, null, [ + 'path', + 3, + 'to', + 'field', + ]); + + expect(error.toJSON()).to.deep.equal({ + message: 'msg', + locations: undefined, + path: ['path', 3, 'to', 'field'], + }); + }); + + it('includes extension fields', () => { + const error = new GraphQLError('msg', null, null, null, null, null, { + foo: 'bar', + }); + + expect(error.toJSON()).to.deep.equal({ + message: 'msg', + locations: undefined, + path: undefined, + extensions: { foo: 'bar' }, + }); + }); + + it('can be created with full argument list', () => { + const error = new GraphQLError( + 'msg', + [operationNode], + source, + [6], + ['path', 2, 'a'], + new Error('I like turtles'), + { hee: 'I like turtles' }, + ); + + expect(error.toJSON()).to.deep.equal({ + message: 'msg', + locations: [{ column: 5, line: 2 }], + path: ['path', 2, 'a'], + extensions: { hee: 'I like turtles' }, + }); + }); +}); diff --git a/src/error/formatError.d.ts b/src/error/formatError.d.ts index fb3451b774..869e16f2e0 100644 --- a/src/error/formatError.d.ts +++ b/src/error/formatError.d.ts @@ -1,40 +1 @@ -import { SourceLocation } from '../language/location'; - -import { GraphQLError } from './GraphQLError'; - -/** - * Given a GraphQLError, format it according to the rules described by the - * Response Format, Errors section of the GraphQL Specification. - */ -export function formatError(error: GraphQLError): GraphQLFormattedError; - -/** - * @see https://github.com/graphql/graphql-spec/blob/master/spec/Section%207%20--%20Response.md#errors - */ -export interface GraphQLFormattedError< - TExtensions extends Record = Record -> { - /** - * A short, human-readable summary of the problem that **SHOULD NOT** change - * from occurrence to occurrence of the problem, except for purposes of - * localization. - */ - readonly message: string; - /** - * If an error can be associated to a particular point in the requested - * GraphQL document, it should contain a list of locations. - */ - readonly locations?: ReadonlyArray; - /** - * If an error can be associated to a particular field in the GraphQL result, - * it _must_ contain an entry with the key `path` that details the path of - * the response field which experienced the error. This allows clients to - * identify whether a null result is intentional or caused by a runtime error. - */ - readonly path?: ReadonlyArray; - /** - * Reserved for implementors to extend the protocol however they see fit, - * and hence there are no additional restrictions on its contents. - */ - readonly extensions?: TExtensions; -} +export { formatError, GraphQLFormattedError } from './GraphQLError';