Skip to content

Commit 01df30f

Browse files
committed
fix(useErrorHandler): handle incremental execution errors
Fixes n1ru4l#2112
1 parent 58d80ea commit 01df30f

File tree

4 files changed

+67
-7
lines changed

4 files changed

+67
-7
lines changed

packages/core/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"tslib": "^2.5.0"
6161
},
6262
"devDependencies": {
63+
"@graphql-tools/executor": "^1.1.0",
6364
"@graphql-tools/schema": "10.0.2",
6465
"@graphql-tools/utils": "10.0.11",
6566
"@repeaterjs/repeater": "3.0.5",

packages/core/src/plugins/use-error-handler.ts

+19-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { DefaultContext, ExecutionResult, Plugin, TypedExecutionArgs } from '@envelop/types';
1+
import {
2+
DefaultContext,
3+
ExecutionResult,
4+
IncrementalExecutionResult,
5+
Plugin,
6+
TypedExecutionArgs,
7+
} from '@envelop/types';
28
import { handleStreamOrSingleExecutionResult } from '../utils.js';
39
import { isGraphQLError, SerializableGraphQLErrorLike } from './use-masked-errors.js';
410

@@ -13,15 +19,24 @@ export type ErrorHandler = ({
1319
}) => void;
1420

1521
type ErrorHandlerCallback<ContextType> = {
16-
result: ExecutionResult;
22+
result: ExecutionResult | IncrementalExecutionResult;
1723
args: TypedExecutionArgs<ContextType>;
1824
};
1925

2026
const makeHandleResult =
2127
<ContextType extends Record<any, any>>(errorHandler: ErrorHandler) =>
2228
({ result, args }: ErrorHandlerCallback<ContextType>) => {
23-
if (result.errors?.length) {
24-
errorHandler({ errors: result.errors, context: args, phase: 'execution' });
29+
const errors = result.errors ? [...result.errors] : [];
30+
if ('incremental' in result && result.incremental) {
31+
for (const increment of result.incremental) {
32+
if (increment.errors) {
33+
errors.push(...increment.errors);
34+
}
35+
}
36+
}
37+
38+
if (errors.length) {
39+
errorHandler({ errors, context: args, phase: 'execution' });
2540
}
2641
};
2742

packages/core/test/plugins/use-error-handler.spec.ts

+43-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
import { useExtendContext } from '@envelop/core';
1+
import * as GraphQLJS from 'graphql';
2+
import { useEngine, useExtendContext } from '@envelop/core';
23
import {
34
assertStreamExecutionValue,
45
collectAsyncIteratorValues,
56
createTestkit,
67
} from '@envelop/testing';
7-
import { Plugin } from '@envelop/types';
8+
import { ExecutionResult, IncrementalExecutionResult, Plugin } from '@envelop/types';
9+
import { normalizedExecutor } from '@graphql-tools/executor';
810
import { makeExecutableSchema } from '@graphql-tools/schema';
911
import { createGraphQLError } from '@graphql-tools/utils';
1012
import { Repeater } from '@repeaterjs/repeater';
@@ -139,4 +141,43 @@ describe('useErrorHandler', () => {
139141
}),
140142
);
141143
});
144+
145+
it('should invoke error handler when error happens during incremental execution', async () => {
146+
const schema = makeExecutableSchema({
147+
typeDefs: /* GraphQL */ `
148+
directive @defer on FRAGMENT_SPREAD | INLINE_FRAGMENT
149+
150+
type Query {
151+
foo: String
152+
}
153+
`,
154+
resolvers: {
155+
Query: {
156+
foo: () => {
157+
throw new Error('kaboom');
158+
},
159+
},
160+
},
161+
});
162+
163+
const mockHandler = jest.fn();
164+
const testInstance = createTestkit(
165+
[
166+
useEngine({ ...GraphQLJS, execute: normalizedExecutor, subscribe: normalizedExecutor }),
167+
useErrorHandler(mockHandler),
168+
],
169+
schema,
170+
);
171+
const result = (await testInstance.execute(`query { ... @defer { foo } }`)) as
172+
| ExecutionResult
173+
| IncrementalExecutionResult
174+
| AsyncIterableIterator<ExecutionResult>
175+
| AsyncIterableIterator<IncrementalExecutionResult>;
176+
if ('next' in result) {
177+
for await (const _r of result) {
178+
}
179+
}
180+
181+
expect(mockHandler).toHaveBeenCalledWith(expect.objectContaining({ phase: 'execution' }));
182+
});
142183
});

pnpm-lock.yaml

+4-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)