Skip to content

Commit 8e54e58

Browse files
feat: Allow configuration of graphql execution options(maxCoercionErrors)
feat: Allow configuration of graphql execution options(maxCoercionErrors)
1 parent d11401b commit 8e54e58

File tree

7 files changed

+80
-0
lines changed

7 files changed

+80
-0
lines changed

.changeset/curly-friends-argue.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@apollo/server': minor
3+
---
4+
5+
Allow configuration of graphql execution options (maxCoercionErrors)
6+
7+
```js
8+
const server = new ApolloServer({
9+
typeDefs,
10+
resolvers,
11+
executionOptions: {
12+
maxCoercionErrors: 50,
13+
},
14+
});
15+
```

docs/source/api/apollo-server.mdx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,35 @@ An object that specifies how your server parses GraphQL operations. [See `graphq
504504
<tr>
505505
<td>
506506

507+
###### `executionOptions`
508+
509+
`Object`
510+
511+
</td>
512+
<td>
513+
514+
An object that specifies options for GraphQL execution. This object is passed directly to the GraphQL execution engine and supports all [GraphQL-JS execution options](https://www.graphql-js.org/api-v16/execution/).
515+
516+
The most common use case is configuring `maxCoercionErrors` to control how many variable coercion errors are allowed before execution is terminated:
517+
518+
```js
519+
const server = new ApolloServer({
520+
typeDefs,
521+
resolvers,
522+
executionOptions: {
523+
maxCoercionErrors: 10, // Default is 50
524+
},
525+
});
526+
```
527+
528+
GraphQL execution terminates if variable coercion encounters more errors than the specified limit. This prevents your application from performing expensive operations when many input variables are malformed.
529+
530+
</td>
531+
</tr>
532+
533+
<tr>
534+
<td>
535+
507536
###### `nodeEnv`
508537

509538
`string`

docs/source/data/errors.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ description: Making errors actionable on the client and server
55

66
import TopLevelAwait from "../shared/top-level-await.mdx"
77

8+
Use the [<code>executionOptions</code> option](../api/apollo-server#executionoptions) to configure how many variable coercion errors are allowed before execution terminates.
9+
810
<!-- cSpell:ignore typenam -->
911

1012
Whenever Apollo Server encounters errors while processing a GraphQL operation, its response to the client includes an `errors` array containing each error that occurred. Each error in the array has an `extensions` field that provides additional useful information, including an error `code` and (while in development mode) a `stacktrace`.

packages/server/src/ApolloServer.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
print,
1616
printSchema,
1717
type DocumentNode,
18+
type ExecutionArgs,
1819
type FormattedExecutionResult,
1920
type GraphQLFieldResolver,
2021
type GraphQLFormattedError,
@@ -153,6 +154,7 @@ export interface ApolloServerInternals<TContext extends BaseContext> {
153154
apolloConfig: ApolloConfig;
154155
plugins: ApolloServerPlugin<TContext>[];
155156
parseOptions: ParseOptions;
157+
executionOptions?: ExecutionArgs['options'];
156158
// `undefined` means we figure out what to do during _start (because
157159
// the default depends on whether or not we used the background version
158160
// of start).
@@ -335,6 +337,7 @@ export class ApolloServer<in out TContext extends BaseContext = BaseContext> {
335337
// `start()` will call `addDefaultPlugins` to add default plugins.
336338
plugins: config.plugins ?? [],
337339
parseOptions: config.parseOptions ?? {},
340+
executionOptions: config.executionOptions ?? {},
338341
state,
339342
stopOnTerminationSignals: config.stopOnTerminationSignals,
340343

packages/server/src/__tests__/ApolloServer.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,33 @@ describe('ApolloServer executeOperation', () => {
625625
await server.stop();
626626
});
627627

628+
it('variable coercion errors, configure max number of errors', async () => {
629+
const server = new ApolloServer({
630+
typeDefs,
631+
resolvers,
632+
executionOptions: {
633+
maxCoercionErrors: 1,
634+
},
635+
});
636+
await server.start();
637+
const { body, http } = await server.executeOperation({
638+
query: `#graphql
639+
query NeedsArg($arg: CompoundInput!) { needsCompoundArg(aCompound: $arg) }
640+
`,
641+
variables: {
642+
arg: { compound: { error1: '1', error2: '2', error3: '3' } },
643+
},
644+
});
645+
const result = singleResult(body);
646+
expect(result.errors).toHaveLength(2);
647+
expect(result.errors?.[0].extensions?.code).toBe('BAD_USER_INPUT');
648+
expect(result.errors?.[1].extensions?.code).toBe('INTERNAL_SERVER_ERROR');
649+
expect(result.errors?.[1].message).toMatch(
650+
'Too many errors processing variables, error limit reached. Execution aborted.',
651+
);
652+
expect(http.status).toBe(400);
653+
});
654+
628655
it('passes its second argument as context object', async () => {
629656
const server = new ApolloServer({
630657
typeDefs,

packages/server/src/externalTypes/constructor.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type { Logger } from '@apollo/utils.logger';
88
import type { IExecutableSchemaDefinition } from '@graphql-tools/schema';
99
import type {
1010
DocumentNode,
11+
ExecutionArgs,
1112
FormattedExecutionResult,
1213
GraphQLFieldResolver,
1314
GraphQLFormattedError,
@@ -114,6 +115,8 @@ interface ApolloServerOptionsBase<TContext extends BaseContext> {
114115
// parsing the schema.
115116
parseOptions?: ParseOptions;
116117

118+
executionOptions?: ExecutionArgs['options'];
119+
117120
// TODO(AS6): remove this option. Configuration to `true` is default behavior
118121
// and configuration to `false` is deprecated. If you depend on `false`
119122
// behavior, we recommend migrating away from that at your earliest

packages/server/src/requestPipeline.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,7 @@ export async function processGraphQLRequest<TContext extends BaseContext>(
584584
operationName: request.operationName,
585585
fieldResolver: internals.fieldResolver,
586586
useLegacyIncremental,
587+
options: internals.executionOptions,
587588
legacyExperimentalExecuteIncrementally:
588589
internals.legacyExperimentalExecuteIncrementally,
589590
});

0 commit comments

Comments
 (0)