@@ -13,6 +13,8 @@ import { promiseForObject } from '../jsutils/promiseForObject';
1313import type { PromiseOrValue } from '../jsutils/PromiseOrValue' ;
1414import { promiseReduce } from '../jsutils/promiseReduce' ;
1515
16+ import type { GraphQLErrorBehavior } from '../error/ErrorBehavior' ;
17+ import { isErrorBehavior } from '../error/ErrorBehavior' ;
1618import type { GraphQLFormattedError } from '../error/GraphQLError' ;
1719import { GraphQLError } from '../error/GraphQLError' ;
1820import { locatedError } from '../error/locatedError' ;
@@ -115,6 +117,7 @@ export interface ExecutionContext {
115117 typeResolver : GraphQLTypeResolver < any , any > ;
116118 subscribeFieldResolver : GraphQLFieldResolver < any , any > ;
117119 errors : Array < GraphQLError > ;
120+ errorBehavior : GraphQLErrorBehavior ;
118121}
119122
120123/**
@@ -130,6 +133,7 @@ export interface ExecutionResult<
130133> {
131134 errors ?: ReadonlyArray < GraphQLError > ;
132135 data ?: TData | null ;
136+ onError ?: GraphQLErrorBehavior ;
133137 extensions ?: TExtensions ;
134138}
135139
@@ -152,6 +156,15 @@ export interface ExecutionArgs {
152156 fieldResolver ?: Maybe < GraphQLFieldResolver < any , any > > ;
153157 typeResolver ?: Maybe < GraphQLTypeResolver < any , any > > ;
154158 subscribeFieldResolver ?: Maybe < GraphQLFieldResolver < any , any > > ;
159+ /**
160+ * Experimental. Set to NO_PROPAGATE to prevent error propagation. Set to ABORT to
161+ * abort a request when any error occurs.
162+ *
163+ * Default: PROPAGATE
164+ *
165+ * @experimental
166+ */
167+ onError ?: GraphQLErrorBehavior ;
155168 /** Additional execution options. */
156169 options ?: {
157170 /** Set the maximum number of errors allowed for coercing (defaults to 50). */
@@ -291,9 +304,21 @@ export function buildExecutionContext(
291304 fieldResolver,
292305 typeResolver,
293306 subscribeFieldResolver,
307+ < << << << HEAD
294308 options,
309+ = === ===
310+ onError,
311+ > >>> >>> f3109c39 ( Implement onError proposal)
295312 } = args ;
296313
314+ if ( onError != null && ! isErrorBehavior ( onError ) ) {
315+ return [
316+ new GraphQLError (
317+ 'Unsupported `onError` value; supported values are `PROPAGATE`, `NO_PROPAGATE` and `ABORT`.' ,
318+ ) ,
319+ ] ;
320+ }
321+
297322 let operation : OperationDefinitionNode | undefined ;
298323 const fragments : ObjMap < FragmentDefinitionNode > = Object . create ( null ) ;
299324 for ( const definition of document . definitions ) {
@@ -353,6 +378,7 @@ export function buildExecutionContext(
353378 typeResolver : typeResolver ?? defaultTypeResolver ,
354379 subscribeFieldResolver : subscribeFieldResolver ?? defaultFieldResolver ,
355380 errors : [ ] ,
381+ errorBehavior : onError ?? 'PROPAGATE' ,
356382 } ;
357383}
358384
@@ -591,6 +617,7 @@ export function buildResolveInfo(
591617 rootValue : exeContext . rootValue ,
592618 operation : exeContext . operation ,
593619 variableValues : exeContext . variableValues ,
620+ errorBehavior : exeContext . errorBehavior ,
594621 } ;
595622}
596623
@@ -599,10 +626,25 @@ function handleFieldError(
599626 returnType : GraphQLOutputType ,
600627 exeContext : ExecutionContext ,
601628) : null {
602- // If the field type is non-nullable, then it is resolved without any
603- // protection from errors, however it still properly locates the error.
604- if ( isNonNullType ( returnType ) ) {
629+ if ( exeContext . errorBehavior === 'PROPAGATE' ) {
630+ // If the field type is non-nullable, then it is resolved without any
631+ // protection from errors, however it still properly locates the error.
632+ // Note: semantic non-null types are treated as nullable for the purposes
633+ // of error handling.
634+ if ( isNonNullType ( returnType ) ) {
635+ throw error ;
636+ }
637+ } else if ( exeContext . errorBehavior === 'ABORT' ) {
638+ // In this mode, any error aborts the request
605639 throw error ;
640+ } else if ( exeContext . errorBehavior === 'NO_PROPAGATE' ) {
641+ // In this mode, the client takes responsibility for error handling, so we
642+ // treat the field as if it were nullable.
643+ } else {
644+ invariant (
645+ false ,
646+ 'Unexpected errorBehavior setting: ' + inspect ( exeContext . errorBehavior ) ,
647+ ) ;
606648 }
607649
608650 // Otherwise, error protection is applied, logging the error and resolving
0 commit comments