Skip to content

Commit 3e069f5

Browse files
committed
Add path to formatError
While path was added to the serializable error, it was not yet added to the default formatError function. Adding this is technically breaking since it begins to expose new information from your API.
1 parent 95c1bc2 commit 3e069f5

29 files changed

+211
-86
lines changed

src/error/__tests__/GraphQLError-test.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import { expect } from 'chai';
1111
import { describe, it } from 'mocha';
1212

13-
import { parse, Source, GraphQLError } from '../../';
13+
import { parse, Source, GraphQLError, formatError } from '../../';
1414

1515

1616
describe('GraphQLError', () => {
@@ -123,4 +123,20 @@ describe('GraphQLError', () => {
123123
);
124124
});
125125

126+
it('default error formatter includes path', () => {
127+
const e = new GraphQLError(
128+
'msg',
129+
null,
130+
null,
131+
null,
132+
[ 'path', 3, 'to', 'field' ]
133+
);
134+
135+
expect(formatError(e)).to.deep.equal({
136+
message: 'msg',
137+
locations: undefined,
138+
path: [ 'path', 3, 'to', 'field' ]
139+
});
140+
});
141+
126142
});

src/error/formatError.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ export function formatError(error: GraphQLError): GraphQLFormattedError {
2020
invariant(error, 'Received null or undefined error.');
2121
return {
2222
message: error.message,
23-
locations: error.locations
23+
locations: error.locations,
24+
path: error.path
2425
};
2526
}
2627

2728
export type GraphQLFormattedError = {
2829
message: string,
29-
locations: ?Array<GraphQLErrorLocation>
30+
locations: ?Array<GraphQLErrorLocation>,
31+
path: ?Array<string | number>
3032
};
3133

3234
export type GraphQLErrorLocation = {

src/execution/__tests__/executor-test.js

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -403,27 +403,38 @@ describe('Execute: Handles basic execution tasks', () => {
403403

404404
expect(result.errors && result.errors.map(formatError)).to.deep.equal([
405405
{ message: 'Error getting syncError',
406-
locations: [ { line: 3, column: 7 } ] },
406+
locations: [ { line: 3, column: 7 } ],
407+
path: [ 'syncError' ] },
407408
{ message: 'Error getting syncRawError',
408-
locations: [ { line: 4, column: 7 } ] },
409+
locations: [ { line: 4, column: 7 } ],
410+
path: [ 'syncRawError' ] },
409411
{ message: 'Error getting syncReturnError',
410-
locations: [ { line: 5, column: 7 } ] },
412+
locations: [ { line: 5, column: 7 } ],
413+
path: [ 'syncReturnError' ] },
411414
{ message: 'Error getting syncReturnErrorList1',
412-
locations: [ { line: 6, column: 7 } ] },
415+
locations: [ { line: 6, column: 7 } ],
416+
path: [ 'syncReturnErrorList', 1 ] },
413417
{ message: 'Error getting syncReturnErrorList3',
414-
locations: [ { line: 6, column: 7 } ] },
418+
locations: [ { line: 6, column: 7 } ],
419+
path: [ 'syncReturnErrorList', 3 ] },
415420
{ message: 'Error getting asyncReject',
416-
locations: [ { line: 8, column: 7 } ] },
421+
locations: [ { line: 8, column: 7 } ],
422+
path: [ 'asyncReject' ] },
417423
{ message: 'Error getting asyncRawReject',
418-
locations: [ { line: 9, column: 7 } ] },
424+
locations: [ { line: 9, column: 7 } ],
425+
path: [ 'asyncRawReject' ] },
419426
{ message: 'An unknown error occurred.',
420-
locations: [ { line: 10, column: 7 } ] },
427+
locations: [ { line: 10, column: 7 } ],
428+
path: [ 'asyncEmptyReject' ] },
421429
{ message: 'Error getting asyncError',
422-
locations: [ { line: 11, column: 7 } ] },
430+
locations: [ { line: 11, column: 7 } ],
431+
path: [ 'asyncError' ] },
423432
{ message: 'Error getting asyncRawError',
424-
locations: [ { line: 12, column: 7 } ] },
433+
locations: [ { line: 12, column: 7 } ],
434+
path: [ 'asyncRawError' ] },
425435
{ message: 'Error getting asyncReturnError',
426-
locations: [ { line: 13, column: 7 } ] },
436+
locations: [ { line: 13, column: 7 } ],
437+
path: [ 'asyncReturnError' ] },
427438
]);
428439
});
429440

src/execution/__tests__/lists-test.js

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ describe('Execute: Accepts any iterable as list value', () => {
104104
{ data: { nest: { test: null } },
105105
errors: [ {
106106
message: 'Expected Iterable, but did not find one for field DataType.test.',
107-
locations: [ { line: 1, column: 10 } ]
107+
locations: [ { line: 1, column: 10 } ],
108+
path: [ 'nest', 'test' ]
108109
} ] }
109110
));
110111

@@ -157,7 +158,8 @@ describe('Execute: Handles list nullability', () => {
157158
{ data: { nest: { test: null } },
158159
errors: [
159160
{ message: 'bad',
160-
locations: [ { line: 1, column: 10 } ] }
161+
locations: [ { line: 1, column: 10 } ],
162+
path: [ 'nest', 'test' ] }
161163
] }
162164
));
163165

@@ -180,7 +182,8 @@ describe('Execute: Handles list nullability', () => {
180182
{ data: { nest: { test: [ 1, null, 2 ] } },
181183
errors: [
182184
{ message: 'bad',
183-
locations: [ { line: 1, column: 10 } ] }
185+
locations: [ { line: 1, column: 10 } ],
186+
path: [ 'nest', 'test', 1 ] }
184187
] }
185188
));
186189

@@ -208,7 +211,8 @@ describe('Execute: Handles list nullability', () => {
208211
{ data: { nest: null },
209212
errors: [
210213
{ message: 'Cannot return null for non-nullable field DataType.test.',
211-
locations: [ { line: 1, column: 10 } ] }
214+
locations: [ { line: 1, column: 10 } ],
215+
path: [ 'nest', 'test' ] }
212216
] }
213217
));
214218

@@ -231,7 +235,8 @@ describe('Execute: Handles list nullability', () => {
231235
{ data: { nest: null },
232236
errors: [
233237
{ message: 'Cannot return null for non-nullable field DataType.test.',
234-
locations: [ { line: 1, column: 10 } ] }
238+
locations: [ { line: 1, column: 10 } ],
239+
path: [ 'nest', 'test' ] }
235240
] }
236241
));
237242

@@ -240,7 +245,8 @@ describe('Execute: Handles list nullability', () => {
240245
{ data: { nest: null },
241246
errors: [
242247
{ message: 'bad',
243-
locations: [ { line: 1, column: 10 } ] }
248+
locations: [ { line: 1, column: 10 } ],
249+
path: [ 'nest', 'test' ] }
244250
] }
245251
));
246252

@@ -263,7 +269,8 @@ describe('Execute: Handles list nullability', () => {
263269
{ data: { nest: { test: [ 1, null, 2 ] } },
264270
errors: [
265271
{ message: 'bad',
266-
locations: [ { line: 1, column: 10 } ] }
272+
locations: [ { line: 1, column: 10 } ],
273+
path: [ 'nest', 'test', 1 ] }
267274
] }
268275
));
269276

@@ -286,7 +293,8 @@ describe('Execute: Handles list nullability', () => {
286293
{ data: { nest: { test: null } },
287294
errors: [
288295
{ message: 'Cannot return null for non-nullable field DataType.test.',
289-
locations: [ { line: 1, column: 10 } ] }
296+
locations: [ { line: 1, column: 10 } ],
297+
path: [ 'nest', 'test', 1 ] }
290298
] }
291299
));
292300

@@ -309,7 +317,8 @@ describe('Execute: Handles list nullability', () => {
309317
{ data: { nest: { test: null } },
310318
errors: [
311319
{ message: 'Cannot return null for non-nullable field DataType.test.',
312-
locations: [ { line: 1, column: 10 } ] }
320+
locations: [ { line: 1, column: 10 } ],
321+
path: [ 'nest', 'test', 1 ] }
313322
] }
314323
));
315324

@@ -323,7 +332,8 @@ describe('Execute: Handles list nullability', () => {
323332
{ data: { nest: { test: null } },
324333
errors: [
325334
{ message: 'bad',
326-
locations: [ { line: 1, column: 10 } ] }
335+
locations: [ { line: 1, column: 10 } ],
336+
path: [ 'nest', 'test' ] }
327337
] }
328338
));
329339

@@ -341,7 +351,8 @@ describe('Execute: Handles list nullability', () => {
341351
{ data: { nest: { test: null } },
342352
errors: [
343353
{ message: 'Cannot return null for non-nullable field DataType.test.',
344-
locations: [ { line: 1, column: 10 } ] }
354+
locations: [ { line: 1, column: 10 } ],
355+
path: [ 'nest', 'test', 1 ] }
345356
] }
346357
));
347358

@@ -350,7 +361,8 @@ describe('Execute: Handles list nullability', () => {
350361
{ data: { nest: { test: null } },
351362
errors: [
352363
{ message: 'bad',
353-
locations: [ { line: 1, column: 10 } ] }
364+
locations: [ { line: 1, column: 10 } ],
365+
path: [ 'nest', 'test', 1 ] }
354366
] }
355367
));
356368

@@ -375,7 +387,8 @@ describe('Execute: Handles list nullability', () => {
375387
{ data: { nest: null },
376388
errors: [
377389
{ message: 'Cannot return null for non-nullable field DataType.test.',
378-
locations: [ { line: 1, column: 10 } ] }
390+
locations: [ { line: 1, column: 10 } ],
391+
path: [ 'nest', 'test', 1 ] }
379392
] }
380393
));
381394

@@ -384,7 +397,8 @@ describe('Execute: Handles list nullability', () => {
384397
{ data: { nest: null },
385398
errors: [
386399
{ message: 'Cannot return null for non-nullable field DataType.test.',
387-
locations: [ { line: 1, column: 10 } ] }
400+
locations: [ { line: 1, column: 10 } ],
401+
path: [ 'nest', 'test' ] }
388402
] }
389403
));
390404

@@ -402,7 +416,8 @@ describe('Execute: Handles list nullability', () => {
402416
{ data: { nest: null },
403417
errors: [
404418
{ message: 'Cannot return null for non-nullable field DataType.test.',
405-
locations: [ { line: 1, column: 10 } ] }
419+
locations: [ { line: 1, column: 10 } ],
420+
path: [ 'nest', 'test', 1 ] }
406421
] }
407422
));
408423

@@ -411,7 +426,8 @@ describe('Execute: Handles list nullability', () => {
411426
{ data: { nest: null },
412427
errors: [
413428
{ message: 'Cannot return null for non-nullable field DataType.test.',
414-
locations: [ { line: 1, column: 10 } ] }
429+
locations: [ { line: 1, column: 10 } ],
430+
path: [ 'nest', 'test' ] }
415431
] }
416432
));
417433

@@ -420,7 +436,8 @@ describe('Execute: Handles list nullability', () => {
420436
{ data: { nest: null },
421437
errors: [
422438
{ message: 'bad',
423-
locations: [ { line: 1, column: 10 } ] }
439+
locations: [ { line: 1, column: 10 } ],
440+
path: [ 'nest', 'test' ] }
424441
] }
425442
));
426443

@@ -438,7 +455,8 @@ describe('Execute: Handles list nullability', () => {
438455
{ data: { nest: null },
439456
errors: [
440457
{ message: 'Cannot return null for non-nullable field DataType.test.',
441-
locations: [ { line: 1, column: 10 } ] }
458+
locations: [ { line: 1, column: 10 } ],
459+
path: [ 'nest', 'test', 1 ] }
442460
] }
443461
));
444462

@@ -447,7 +465,8 @@ describe('Execute: Handles list nullability', () => {
447465
{ data: { nest: null },
448466
errors: [
449467
{ message: 'bad',
450-
locations: [ { line: 1, column: 10 } ] }
468+
locations: [ { line: 1, column: 10 } ],
469+
path: [ 'nest', 'test', 1 ] }
451470
] }
452471
));
453472

src/validation/__tests__/ArgumentsOfCorrectType-test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ function badValue(argName, typeName, value, line, column, errors) {
2727
return {
2828
message: badValueMessage(argName, typeName, value, realErrors),
2929
locations: [ { line, column } ],
30+
path: undefined,
3031
};
3132
}
3233

src/validation/__tests__/DefaultValuesOfCorrectType-test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ function defaultForNonNullArg(varName, typeName, guessTypeName, line, column) {
2020
return {
2121
message: defaultForNonNullArgMessage(varName, typeName, guessTypeName),
2222
locations: [ { line, column } ],
23+
path: undefined,
2324
};
2425
}
2526

@@ -35,6 +36,7 @@ function badValue(varName, typeName, val, line, column, errors) {
3536
return {
3637
message: badValueForDefaultArgMessage(varName, typeName, val, realErrors),
3738
locations: [ { line, column } ],
39+
path: undefined,
3840
};
3941
}
4042

src/validation/__tests__/FieldsOnCorrectType-test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ function undefinedField(
3232
suggestedFields
3333
),
3434
locations: [ { line, column } ],
35+
path: undefined,
3536
};
3637
}
3738

src/validation/__tests__/FragmentsOnCompositeTypes-test.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ function error(fragName, typeName, line, column) {
1919
return {
2020
message: fragmentOnNonCompositeErrorMessage(fragName, typeName),
2121
locations: [ { line, column } ],
22+
path: undefined,
2223
};
2324
}
2425

@@ -101,7 +102,8 @@ describe('Validate: Fragments on composite types', () => {
101102
}
102103
`, [
103104
{ message: inlineFragmentOnNonCompositeErrorMessage('String'),
104-
locations: [ { line: 3, column: 16 } ] }
105+
locations: [ { line: 3, column: 16 } ],
106+
path: undefined }
105107
]);
106108
});
107109

src/validation/__tests__/KnownArgumentNames-test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ function unknownArg(argName, fieldName, typeName, suggestedArgs, line, column) {
2020
return {
2121
message: unknownArgMessage(argName, fieldName, typeName, suggestedArgs),
2222
locations: [ { line, column } ],
23+
path: undefined,
2324
};
2425
}
2526

@@ -33,6 +34,7 @@ function unknownDirectiveArg(
3334
return {
3435
message: unknownDirectiveArgMessage(argName, directiveName, suggestedArgs),
3536
locations: [ { line, column } ],
37+
path: undefined,
3638
};
3739
}
3840

src/validation/__tests__/KnownDirectives-test.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,16 @@ import {
2222
function unknownDirective(directiveName, line, column) {
2323
return {
2424
message: unknownDirectiveMessage(directiveName),
25-
locations: [ { line, column } ]
25+
locations: [ { line, column } ],
26+
path: undefined,
2627
};
2728
}
2829

2930
function misplacedDirective(directiveName, placement, line, column) {
3031
return {
3132
message: misplacedDirectiveMessage(directiveName, placement),
32-
locations: [ { line, column } ]
33+
locations: [ { line, column } ],
34+
path: undefined,
3335
};
3436
}
3537

0 commit comments

Comments
 (0)