Skip to content

Commit 42bb1f4

Browse files
committed
feat(executor): add schema coordinates extension to graphql errors
1 parent 447406f commit 42bb1f4

File tree

3 files changed

+37
-16
lines changed

3 files changed

+37
-16
lines changed

packages/executor/src/execution/execute.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import {
2121
isNonNullType,
2222
isObjectType,
2323
Kind,
24-
locatedError,
2524
OperationDefinitionNode,
2625
SchemaMetaFieldDef,
2726
TypeMetaFieldDef,
@@ -58,6 +57,7 @@ import { createDeferredPromise, handleMaybePromise } from '@whatwg-node/promise-
5857
import { coerceError } from './coerceError.js';
5958
import { flattenAsyncIterable } from './flattenAsyncIterable.js';
6059
import { invariant } from './invariant.js';
60+
import { locatedError } from './locatedError.js';
6161
import { promiseForObject } from './promiseForObject.js';
6262
import { getVariableValues } from './values.js';
6363

@@ -746,14 +746,14 @@ function executeField(
746746
let result: unknown;
747747
for (let rawErrorItem of rawError.errors) {
748748
rawErrorItem = coerceError(rawErrorItem);
749-
const error = locatedError(rawErrorItem, fieldNodes, pathToArray(path));
749+
const error = locatedError(rawErrorItem, fieldNodes, pathToArray(path), info);
750750
result = handleFieldError(error, returnType, errors);
751751
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord);
752752
}
753753
return result;
754754
}
755755
rawError = coerceError(rawError);
756-
const error = locatedError(rawError, fieldNodes, pathToArray(path));
756+
const error = locatedError(rawError, fieldNodes, pathToArray(path), info);
757757
const handledError = handleFieldError(error, returnType, errors);
758758
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord);
759759
return handledError;
@@ -765,14 +765,14 @@ function executeField(
765765
let result: unknown;
766766
for (let rawErrorItem of rawError.errors) {
767767
rawErrorItem = coerceError(rawErrorItem);
768-
const error = locatedError(rawErrorItem, fieldNodes, pathToArray(path));
768+
const error = locatedError(rawErrorItem, fieldNodes, pathToArray(path), info);
769769
result = handleFieldError(error, returnType, errors);
770770
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord);
771771
}
772772
return result;
773773
}
774774
const coercedError = coerceError(rawError);
775-
const error = locatedError(coercedError, fieldNodes, pathToArray(path));
775+
const error = locatedError(coercedError, fieldNodes, pathToArray(path), info);
776776
const handledError = handleFieldError(error, returnType, errors);
777777
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord);
778778
return handledError;
@@ -1041,7 +1041,7 @@ async function completeAsyncIteratorValue(
10411041
}
10421042
} catch (rawError) {
10431043
const coercedError = coerceError(rawError);
1044-
const error = locatedError(coercedError, fieldNodes, pathToArray(itemPath));
1044+
const error = locatedError(coercedError, fieldNodes, pathToArray(itemPath), info);
10451045
completedResults.push(handleFieldError(error, itemType, errors));
10461046
break;
10471047
}
@@ -1201,7 +1201,7 @@ function completeListItemValue(
12011201
completedResults.push(
12021202
completedItem.then(undefined, rawError => {
12031203
rawError = coerceError(rawError);
1204-
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath));
1204+
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath), info);
12051205
const handledError = handleFieldError(error, itemType, errors);
12061206
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
12071207
return handledError;
@@ -1214,7 +1214,7 @@ function completeListItemValue(
12141214
completedResults.push(completedItem);
12151215
} catch (rawError) {
12161216
const coercedError = coerceError(rawError);
1217-
const error = locatedError(coercedError, fieldNodes, pathToArray(itemPath));
1217+
const error = locatedError(coercedError, fieldNodes, pathToArray(itemPath), info);
12181218
const handledError = handleFieldError(error, itemType, errors);
12191219
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
12201220
completedResults.push(handledError);
@@ -1789,13 +1789,13 @@ function executeSubscription(exeContext: ExecutionContext): MaybePromise<AsyncIt
17891789
return result
17901790
.then(result => assertEventStream(result, exeContext.signal, exeContext.onSignalAbort))
17911791
.then(undefined, error => {
1792-
throw locatedError(error, fieldNodes, pathToArray(path));
1792+
throw locatedError(error, fieldNodes, pathToArray(path), info);
17931793
});
17941794
}
17951795

17961796
return assertEventStream(result, exeContext.signal, exeContext.onSignalAbort);
17971797
} catch (error) {
1798-
throw locatedError(error, fieldNodes, pathToArray(path));
1798+
throw locatedError(error, fieldNodes, pathToArray(path), info);
17991799
}
18001800
}
18011801

@@ -1921,15 +1921,15 @@ function executeStreamField(
19211921
// to take a second callback for the error case.
19221922
completedItem = completedItem.then(undefined, rawError => {
19231923
rawError = coerceError(rawError);
1924-
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath));
1924+
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath), info);
19251925
const handledError = handleFieldError(error, itemType, asyncPayloadRecord.errors);
19261926
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
19271927
return handledError;
19281928
});
19291929
}
19301930
} catch (rawError) {
19311931
const coercedError = coerceError(rawError);
1932-
const error = locatedError(coercedError, fieldNodes, pathToArray(itemPath));
1932+
const error = locatedError(coercedError, fieldNodes, pathToArray(itemPath), info);
19331933
completedItem = handleFieldError(error, itemType, asyncPayloadRecord.errors);
19341934
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
19351935
}
@@ -1977,7 +1977,7 @@ async function executeStreamIteratorItem(
19771977
item = value;
19781978
} catch (rawError) {
19791979
const coercedError = coerceError(rawError);
1980-
const error = locatedError(coercedError, fieldNodes, pathToArray(itemPath));
1980+
const error = locatedError(coercedError, fieldNodes, pathToArray(itemPath), info);
19811981
const value = handleFieldError(error, itemType, asyncPayloadRecord.errors);
19821982
// don't continue if iterator throws
19831983
return { done: true, value };
@@ -1996,15 +1996,15 @@ async function executeStreamIteratorItem(
19961996

19971997
if (isPromise(completedItem)) {
19981998
completedItem = completedItem.then(undefined, rawError => {
1999-
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath));
1999+
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath), info);
20002000
const handledError = handleFieldError(error, itemType, asyncPayloadRecord.errors);
20012001
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
20022002
return handledError;
20032003
});
20042004
}
20052005
return { done: false, value: completedItem };
20062006
} catch (rawError) {
2007-
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath));
2007+
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath), info);
20082008
const value = handleFieldError(error, itemType, asyncPayloadRecord.errors);
20092009
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
20102010
return { done: false, value };
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import type { ASTNode } from 'graphql';
2+
import { locatedError as _locatedError } from 'graphql/error/locatedError';
3+
import { GraphQLResolveInfo, Maybe } from '@graphql-tools/utils';
4+
5+
export function locatedError(
6+
rawError: unknown,
7+
nodes: ASTNode | ReadonlyArray<ASTNode> | null | undefined,
8+
path: Maybe<ReadonlyArray<string | number>>,
9+
info: GraphQLResolveInfo,
10+
) {
11+
const error = _locatedError(rawError, nodes, path);
12+
error.extensions['schemaCoordinates'] = `${info.parentType.name}.${info.fieldName}`;
13+
return error;
14+
}

packages/utils/src/errors.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ASTNode, GraphQLError, Source, versionInfo } from 'graphql';
2+
import { GraphQLResolveInfo } from './Interfaces.js';
23
import { Maybe } from './types.js';
34

45
interface GraphQLErrorOptions {
@@ -63,13 +64,19 @@ export function createGraphQLError(message: string, options?: GraphQLErrorOption
6364
export function relocatedError(
6465
originalError: GraphQLError,
6566
path?: ReadonlyArray<string | number>,
67+
info?: Maybe<GraphQLResolveInfo>,
6668
): GraphQLError {
6769
return createGraphQLError(originalError.message, {
6870
nodes: originalError.nodes,
6971
source: originalError.source,
7072
positions: originalError.positions,
7173
path: path == null ? originalError.path : path,
7274
originalError,
73-
extensions: originalError.extensions,
75+
extensions: info
76+
? {
77+
...originalError.extensions,
78+
schemaCoordinates: `${info.parentType.name}.${info.fieldName}`,
79+
}
80+
: originalError.extensions,
7481
});
7582
}

0 commit comments

Comments
 (0)