Skip to content

Commit 2065e70

Browse files
authored
Backport GraphQLError toJSON method to v15 (#4324)
Eases up the transition to future v17 that has completely removed the `formatError` utility.
1 parent 511e0f1 commit 2065e70

File tree

4 files changed

+98
-40
lines changed

4 files changed

+98
-40
lines changed

src/error/GraphQLError.d.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,51 @@ export class GraphQLError extends Error {
8282
* Extension fields to add to the formatted error.
8383
*/
8484
readonly extensions: { [key: string]: any };
85+
86+
toString(): string;
87+
88+
toJSON(): GraphQLFormattedError;
8589
}
8690

8791
/**
8892
* Prints a GraphQLError to a string, representing useful location information
8993
* about the error's position in the source.
9094
*/
9195
export function printError(error: GraphQLError): string;
96+
97+
/**
98+
* Given a GraphQLError, format it according to the rules described by the
99+
* Response Format, Errors section of the GraphQL Specification.
100+
*/
101+
export function formatError(error: GraphQLError): GraphQLFormattedError;
102+
103+
/**
104+
* @see https://github.com/graphql/graphql-spec/blob/master/spec/Section%207%20--%20Response.md#errors
105+
*/
106+
export interface GraphQLFormattedError<
107+
TExtensions extends Record<string, any> = Record<string, any>
108+
> {
109+
/**
110+
* A short, human-readable summary of the problem that **SHOULD NOT** change
111+
* from occurrence to occurrence of the problem, except for purposes of
112+
* localization.
113+
*/
114+
readonly message: string;
115+
/**
116+
* If an error can be associated to a particular point in the requested
117+
* GraphQL document, it should contain a list of locations.
118+
*/
119+
readonly locations?: ReadonlyArray<SourceLocation>;
120+
/**
121+
* If an error can be associated to a particular field in the GraphQL result,
122+
* it _must_ contain an entry with the key `path` that details the path of
123+
* the response field which experienced the error. This allows clients to
124+
* identify whether a null result is intentional or caused by a runtime error.
125+
*/
126+
readonly path?: ReadonlyArray<string | number>;
127+
/**
128+
* Reserved for implementors to extend the protocol however they see fit,
129+
* and hence there are no additional restrictions on its contents.
130+
*/
131+
readonly extensions?: TExtensions;
132+
}

src/error/GraphQLError.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import type { SourceLocation } from '../language/location';
77
import { getLocation } from '../language/location';
88
import { printLocation, printSourceLocation } from '../language/printLocation';
99

10+
import { formatError } from './formatError';
11+
import type { GraphQLFormattedError } from './formatError';
12+
1013
/**
1114
* A GraphQLError describes an Error found during the parse, validate, or
1215
* execute phases of performing a GraphQL operation. In addition to a message
@@ -157,6 +160,10 @@ export class GraphQLError extends Error {
157160
return printError(this);
158161
}
159162

163+
toJSON(): GraphQLFormattedError {
164+
return formatError(this);
165+
}
166+
160167
// FIXME: workaround to not break chai comparisons, should be remove in v16
161168
// $FlowFixMe[unsupported-syntax] Flow doesn't support computed properties yet
162169
get [SYMBOL_TO_STRING_TAG](): string {

src/error/__tests__/GraphQLError-test.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,3 +293,52 @@ describe('printError', () => {
293293
`);
294294
});
295295
});
296+
297+
describe('toJSON', () => {
298+
it('includes path', () => {
299+
const error = new GraphQLError('msg', null, null, null, [
300+
'path',
301+
3,
302+
'to',
303+
'field',
304+
]);
305+
306+
expect(error.toJSON()).to.deep.equal({
307+
message: 'msg',
308+
locations: undefined,
309+
path: ['path', 3, 'to', 'field'],
310+
});
311+
});
312+
313+
it('includes extension fields', () => {
314+
const error = new GraphQLError('msg', null, null, null, null, null, {
315+
foo: 'bar',
316+
});
317+
318+
expect(error.toJSON()).to.deep.equal({
319+
message: 'msg',
320+
locations: undefined,
321+
path: undefined,
322+
extensions: { foo: 'bar' },
323+
});
324+
});
325+
326+
it('can be created with full argument list', () => {
327+
const error = new GraphQLError(
328+
'msg',
329+
[operationNode],
330+
source,
331+
[6],
332+
['path', 2, 'a'],
333+
new Error('I like turtles'),
334+
{ hee: 'I like turtles' },
335+
);
336+
337+
expect(error.toJSON()).to.deep.equal({
338+
message: 'msg',
339+
locations: [{ column: 5, line: 2 }],
340+
path: ['path', 2, 'a'],
341+
extensions: { hee: 'I like turtles' },
342+
});
343+
});
344+
});

src/error/formatError.d.ts

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1 @@
1-
import { SourceLocation } from '../language/location';
2-
3-
import { GraphQLError } from './GraphQLError';
4-
5-
/**
6-
* Given a GraphQLError, format it according to the rules described by the
7-
* Response Format, Errors section of the GraphQL Specification.
8-
*/
9-
export function formatError(error: GraphQLError): GraphQLFormattedError;
10-
11-
/**
12-
* @see https://github.com/graphql/graphql-spec/blob/master/spec/Section%207%20--%20Response.md#errors
13-
*/
14-
export interface GraphQLFormattedError<
15-
TExtensions extends Record<string, any> = Record<string, any>
16-
> {
17-
/**
18-
* A short, human-readable summary of the problem that **SHOULD NOT** change
19-
* from occurrence to occurrence of the problem, except for purposes of
20-
* localization.
21-
*/
22-
readonly message: string;
23-
/**
24-
* If an error can be associated to a particular point in the requested
25-
* GraphQL document, it should contain a list of locations.
26-
*/
27-
readonly locations?: ReadonlyArray<SourceLocation>;
28-
/**
29-
* If an error can be associated to a particular field in the GraphQL result,
30-
* it _must_ contain an entry with the key `path` that details the path of
31-
* the response field which experienced the error. This allows clients to
32-
* identify whether a null result is intentional or caused by a runtime error.
33-
*/
34-
readonly path?: ReadonlyArray<string | number>;
35-
/**
36-
* Reserved for implementors to extend the protocol however they see fit,
37-
* and hence there are no additional restrictions on its contents.
38-
*/
39-
readonly extensions?: TExtensions;
40-
}
1+
export { formatError, GraphQLFormattedError } from './GraphQLError';

0 commit comments

Comments
 (0)