diff --git a/src/HotChocolate/Adapters/src/Adapters.OpenApi.Core/Execution/DynamicEndpointMiddleware.cs b/src/HotChocolate/Adapters/src/Adapters.OpenApi.Core/Execution/DynamicEndpointMiddleware.cs index 436c6b24970..3852f7b89db 100644 --- a/src/HotChocolate/Adapters/src/Adapters.OpenApi.Core/Execution/DynamicEndpointMiddleware.cs +++ b/src/HotChocolate/Adapters/src/Adapters.OpenApi.Core/Execution/DynamicEndpointMiddleware.cs @@ -69,7 +69,7 @@ await Results.Problem( var requestBuilder = OperationRequestBuilder.New() .SetDocument(endpointDescriptor.Document) - .SetErrorHandlingMode(ErrorHandlingMode.Halt) + .SetErrorHandlingMode(ErrorHandlingMode.Propagate) .SetVariableValues(variables); await session.OnCreateAsync(context, requestBuilder, cancellationToken); diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Parsers/DefaultHttpRequestParser.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Parsers/DefaultHttpRequestParser.cs index d0fc737cd0b..8045ae8d2fe 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Parsers/DefaultHttpRequestParser.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Parsers/DefaultHttpRequestParser.cs @@ -228,11 +228,7 @@ public GraphQLRequest ParseRequestFromParams(IQueryCollection parameters) extensions = JsonDocument.Parse(se); } - ErrorHandlingMode? errorHandlingMode = null; - if (!string.IsNullOrEmpty(onError)) - { - errorHandlingMode = ParseErrorHandlingMode(onError); - } + var errorHandlingMode = ParseErrorHandlingMode(onError); return new GraphQLRequest( document, @@ -327,8 +323,13 @@ public GraphQLRequest ParsePersistedOperationRequestFromParams( return (documentHash, document); } - private static ErrorHandlingMode? ParseErrorHandlingMode(string onError) + private static ErrorHandlingMode? ParseErrorHandlingMode(string? onError) { + if (string.IsNullOrEmpty(onError)) + { + return null; + } + if (onError.Equals("PROPAGATE", StringComparison.OrdinalIgnoreCase)) { return ErrorHandlingMode.Propagate; @@ -339,12 +340,8 @@ public GraphQLRequest ParsePersistedOperationRequestFromParams( return ErrorHandlingMode.Null; } - if (onError.Equals("HALT", StringComparison.OrdinalIgnoreCase)) - { - return ErrorHandlingMode.Halt; - } - - return null; + throw new InvalidGraphQLRequestException( + $"Unknown 'onError' value '{onError}'. Allowed values are 'PROPAGATE' or 'NULL'."); } public GraphQLRequest[] ParseRequest(string sourceText) diff --git a/src/HotChocolate/AspNetCore/src/Transport.Abstractions/Serialization/Utf8JsonWriterHelper.cs b/src/HotChocolate/AspNetCore/src/Transport.Abstractions/Serialization/Utf8JsonWriterHelper.cs index 7f4481f21ec..7429617310c 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Abstractions/Serialization/Utf8JsonWriterHelper.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Abstractions/Serialization/Utf8JsonWriterHelper.cs @@ -728,7 +728,6 @@ private static string GetErrorHandlingModeAsString(ErrorHandlingMode mode) { ErrorHandlingMode.Propagate => "PROPAGATE", ErrorHandlingMode.Null => "NULL", - ErrorHandlingMode.Halt => "HALT", _ => throw new ArgumentOutOfRangeException(nameof(mode)) }; } diff --git a/src/HotChocolate/AspNetCore/src/Transport.Http/DefaultGraphQLHttpClient.cs b/src/HotChocolate/AspNetCore/src/Transport.Http/DefaultGraphQLHttpClient.cs index 049d6020b0c..a52f23dad45 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Http/DefaultGraphQLHttpClient.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Http/DefaultGraphQLHttpClient.cs @@ -599,7 +599,6 @@ private static string GetErrorHandlingModeAsString(ErrorHandlingMode mode) { ErrorHandlingMode.Propagate => "PROPAGATE", ErrorHandlingMode.Null => "NULL", - ErrorHandlingMode.Halt => "HALT", _ => throw new ArgumentOutOfRangeException(nameof(mode)) }; } diff --git a/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/GraphQLOverHttpSpecTests.cs b/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/GraphQLOverHttpSpecTests.cs index b6889e150e3..79c15941fd3 100644 --- a/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/GraphQLOverHttpSpecTests.cs +++ b/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/GraphQLOverHttpSpecTests.cs @@ -540,6 +540,27 @@ public async Task After_Execution_StatusCode_Is_200() Assert.Equal(OK, response.StatusCode); } + [Fact] + public async Task Unknown_OnError_Value_Returns_BadRequest() + { + // arrange + var client = GetClient(Latest); + + // act + using var request = new HttpRequestMessage(HttpMethod.Post, s_url); + request.Content = new StringContent( + """{"query":"{ __typename }","onError":"HALT"}""", + System.Text.Encoding.UTF8, + "application/json"); + + using var response = await client.SendAsync(request); + + // assert + Assert.Equal(BadRequest, response.StatusCode); + var body = await response.Content.ReadAsStringAsync(); + Assert.Contains("onError", body, StringComparison.OrdinalIgnoreCase); + } + private HttpClient GetClient(HttpTransportVersion serverTransportVersion) { var server = CreateStarWarsServer( diff --git a/src/HotChocolate/AspNetCore/test/Transport.Http.Tests/GraphQLHttpClientTests.cs b/src/HotChocolate/AspNetCore/test/Transport.Http.Tests/GraphQLHttpClientTests.cs index bb390f535e8..4a137764c3d 100644 --- a/src/HotChocolate/AspNetCore/test/Transport.Http.Tests/GraphQLHttpClientTests.cs +++ b/src/HotChocolate/AspNetCore/test/Transport.Http.Tests/GraphQLHttpClientTests.cs @@ -442,7 +442,7 @@ public async Task Post_GraphQL_Query_With_OnError() // act var response = await client.PostAsync( - new OperationRequest(query, onError: ErrorHandlingMode.Halt), + new OperationRequest(query, onError: ErrorHandlingMode.Null), cts.Token); // assert @@ -451,7 +451,7 @@ public async Task Post_GraphQL_Query_With_OnError() """ { "data": { - "errorHandlingMode": "HALT" + "errorHandlingMode": "NULL" } } """); @@ -766,7 +766,7 @@ public async Task Get_GraphQL_Query_With_OnError() // act var response = await client.GetAsync( - new OperationRequest(query, onError: ErrorHandlingMode.Halt), + new OperationRequest(query, onError: ErrorHandlingMode.Null), cts.Token); // assert @@ -775,7 +775,7 @@ public async Task Get_GraphQL_Query_With_OnError() """ { "data": { - "errorHandlingMode": "HALT" + "errorHandlingMode": "NULL" } } """); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs index a2929367ce9..de16c1a4d9b 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs @@ -39,6 +39,7 @@ internal sealed partial class OperationContext private int _branchId; private int _variableIndex; private object? _rootValue; + private bool _propagateNullValues; private bool _isInitialized; public OperationContext( @@ -87,6 +88,10 @@ public void Initialize( _batchDispatcher = batchDispatcher; _variableIndex = variableIndex; + var errorHandlingMode = _requestContext.Request.ErrorHandlingMode + ?? _schema.GetOptions().DefaultErrorHandlingMode; + _propagateNullValues = errorHandlingMode is Language.ErrorHandlingMode.Propagate; + IncludeFlags = operation.CreateIncludeFlags(variables); DeferFlags = operation.CreateDeferFlags(variables); Result.Data = new ResultDocument(operation, IncludeFlags); @@ -128,6 +133,7 @@ public void InitializeDeferContext( _currentBranchTracker = context._currentBranchTracker; _currentWorkScheduler = context._currentWorkScheduler; _currentDeferExecutionCoordinator = context._currentDeferExecutionCoordinator; + _propagateNullValues = context._propagateNullValues; _branchId = executionBranchId; _isInitialized = true; @@ -178,6 +184,7 @@ public void Clean() _resolveQueryRootValue = null!; _batchDispatcher = null!; _branchId = int.MinValue; + _propagateNullValues = false; _isInitialized = false; Result.Reset(); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.cs index e912a4dc5bd..d7021e849cc 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.cs @@ -29,6 +29,12 @@ public CancellationToken RequestAborted } } + /// + /// Gets whether null values should be propagated to nullable parents + /// (standard GraphQL behavior). When false, null stays at the field that caused it. + /// + public bool PropagateNullValues => _propagateNullValues; + /// public IFeatureCollection Features { diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/BatchResolverTask.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/BatchResolverTask.cs index 9b5ee8e95b6..c1a7cc19638 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/BatchResolverTask.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/BatchResolverTask.cs @@ -377,7 +377,15 @@ private void CompleteValues( if (resultValue is { IsNullable: false, IsNullOrInvalidated: true }) { - PropagateNullValues(resultValue); + if (_operationContext.PropagateNullValues) + { + PropagateNullValues(resultValue); + } + else + { + resultValue.SetNullValue(); + } + _completionStatus = ExecutionTaskStatus.Faulted; _operationContext.Result.AddNonNullViolation(context.Path); _taskBuffer.Clear(); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs index 74771cf956c..754b29bcc5d 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs @@ -44,7 +44,15 @@ private void CompleteValue(bool success, CancellationToken cancellationToken) if (resultValue is { IsNullable: false, IsNullOrInvalidated: true }) { - PropagateNullValues(resultValue); + if (_operationContext.PropagateNullValues) + { + PropagateNullValues(resultValue); + } + else + { + resultValue.SetNullValue(); + } + _completionStatus = ExecutionTaskStatus.Faulted; _operationContext.Result.AddNonNullViolation(_context.Path); _taskBuffer.Clear(); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs index 82b9974d910..5eb38716281 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs @@ -349,7 +349,15 @@ private static void ResolveAndCompleteInline( if (fieldValue is { IsNullable: false, IsNullOrInvalidated: true }) { - PropagateNullValues(fieldValue); + if (operationContext.PropagateNullValues) + { + PropagateNullValues(fieldValue); + } + else + { + fieldValue.SetNullValue(); + } + operationContext.Result.AddNonNullViolation(fieldValue.Path); } } diff --git a/src/HotChocolate/Core/src/Types/IReadOnlySchemaOptions.cs b/src/HotChocolate/Core/src/Types/IReadOnlySchemaOptions.cs index 73281cd20f7..2729cbe797b 100644 --- a/src/HotChocolate/Core/src/Types/IReadOnlySchemaOptions.cs +++ b/src/HotChocolate/Core/src/Types/IReadOnlySchemaOptions.cs @@ -1,6 +1,7 @@ using System.Reflection; using HotChocolate.Configuration; using HotChocolate.Execution; +using HotChocolate.Language; using HotChocolate.Types; namespace HotChocolate; @@ -230,4 +231,9 @@ public interface IReadOnlySchemaOptions /// Applies the @serializeAs directive to scalar types that specify a serialization format. /// bool ApplySerializeAsToScalars { get; } + + /// + /// Gets the default error handling mode for null propagation. + /// + ErrorHandlingMode DefaultErrorHandlingMode { get; } } diff --git a/src/HotChocolate/Core/src/Types/SchemaOptions.cs b/src/HotChocolate/Core/src/Types/SchemaOptions.cs index ec5f50d5611..54d52b9e17d 100644 --- a/src/HotChocolate/Core/src/Types/SchemaOptions.cs +++ b/src/HotChocolate/Core/src/Types/SchemaOptions.cs @@ -1,6 +1,7 @@ using System.Reflection; using HotChocolate.Configuration; using HotChocolate.Execution; +using HotChocolate.Language; using HotChocolate.Types; namespace HotChocolate; @@ -189,6 +190,9 @@ public int OperationDocumentCacheSize /// public bool ApplySerializeAsToScalars { get; set; } + /// + public ErrorHandlingMode DefaultErrorHandlingMode { get; set; } = ErrorHandlingMode.Propagate; + /// /// Creates a mutable options object from a read-only options object. /// @@ -230,6 +234,7 @@ public static SchemaOptions FromOptions(IReadOnlySchemaOptions options) ApplyShareableToPageInfo = options.ApplyShareableToPageInfo, ApplyShareableToConnections = options.ApplyShareableToConnections, ApplyShareableToNodeFields = options.ApplyShareableToNodeFields, - ApplySerializeAsToScalars = options.ApplySerializeAsToScalars + ApplySerializeAsToScalars = options.ApplySerializeAsToScalars, + DefaultErrorHandlingMode = options.DefaultErrorHandlingMode }; } diff --git a/src/HotChocolate/Core/test/Execution.Abstractions.Tests/Execution/OperationRequestBuilderTests.cs b/src/HotChocolate/Core/test/Execution.Abstractions.Tests/Execution/OperationRequestBuilderTests.cs index a80f53a55ca..c52f227c984 100644 --- a/src/HotChocolate/Core/test/Execution.Abstractions.Tests/Execution/OperationRequestBuilderTests.cs +++ b/src/HotChocolate/Core/test/Execution.Abstractions.Tests/Execution/OperationRequestBuilderTests.cs @@ -315,7 +315,7 @@ public void BuildRequest_SetErrorHandlingMode() var request = OperationRequestBuilder.New() .SetDocument("{ foo }") - .SetErrorHandlingMode(ErrorHandlingMode.Halt) + .SetErrorHandlingMode(ErrorHandlingMode.Null) .Build(); // assert @@ -330,7 +330,7 @@ public void BuildRequest_SetErrorHandlingMode_VariableBatchRequest() var request = OperationRequestBuilder.New() .SetDocument("{ foo }") - .SetErrorHandlingMode(ErrorHandlingMode.Halt) + .SetErrorHandlingMode(ErrorHandlingMode.Null) .SetVariableValues([new Dictionary { ["one"] = "foo" }]) .Build(); diff --git a/src/HotChocolate/Core/test/Execution.Abstractions.Tests/Execution/__snapshots__/OperationRequestBuilderTests.BuildRequest_SetErrorHandlingMode.snap b/src/HotChocolate/Core/test/Execution.Abstractions.Tests/Execution/__snapshots__/OperationRequestBuilderTests.BuildRequest_SetErrorHandlingMode.snap index 6af0dd1b5d2..ef683929c7a 100644 --- a/src/HotChocolate/Core/test/Execution.Abstractions.Tests/Execution/__snapshots__/OperationRequestBuilderTests.BuildRequest_SetErrorHandlingMode.snap +++ b/src/HotChocolate/Core/test/Execution.Abstractions.Tests/Execution/__snapshots__/OperationRequestBuilderTests.BuildRequest_SetErrorHandlingMode.snap @@ -1,4 +1,4 @@ { "document": "{ foo }", - "errorHandlingMode": "Halt" + "errorHandlingMode": "Null" } diff --git a/src/HotChocolate/Core/test/Execution.Abstractions.Tests/Execution/__snapshots__/OperationRequestBuilderTests.BuildRequest_SetErrorHandlingMode_VariableBatchRequest.snap b/src/HotChocolate/Core/test/Execution.Abstractions.Tests/Execution/__snapshots__/OperationRequestBuilderTests.BuildRequest_SetErrorHandlingMode_VariableBatchRequest.snap index 0276b4f5889..1566cd51489 100644 --- a/src/HotChocolate/Core/test/Execution.Abstractions.Tests/Execution/__snapshots__/OperationRequestBuilderTests.BuildRequest_SetErrorHandlingMode_VariableBatchRequest.snap +++ b/src/HotChocolate/Core/test/Execution.Abstractions.Tests/Execution/__snapshots__/OperationRequestBuilderTests.BuildRequest_SetErrorHandlingMode_VariableBatchRequest.snap @@ -1,6 +1,6 @@ { "document": "{ foo }", - "errorHandlingMode": "Halt", + "errorHandlingMode": "Null", "variableValues": [ { "one": "foo" diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/NullErrorPropagationTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Errors/NullErrorPropagationTests.cs index fdad9c24c36..233194550d3 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/NullErrorPropagationTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/NullErrorPropagationTests.cs @@ -1,3 +1,4 @@ +using HotChocolate.Language; using Microsoft.Extensions.DependencyInjection; namespace HotChocolate.Execution; @@ -148,33 +149,191 @@ public async Task Object_NonNullElementHasError(string fieldType) snapshot.Add(result); } - private static async Task CreateExecutorAsync() + [InlineData("nonnull_prop")] + [InlineData("nullable_prop")] + [Theory] + public async Task Object_NonNullElementIsNull_NullMode(string fieldType) { - const string schema = - """ - type Query { - foo: Foo - } - - type Foo { - nullable_list_nullable_element: [Bar] - nonnull_list_nullable_element: [Bar]! - nullable_list_nonnull_element: [Bar!] - nonnull_list_nonnull_element: [Bar!]! - nonnull_prop: Bar! - nullable_prop: Bar - } - - type Bar { - a: String - b: String! - c: String! - } - """; + // arrange + using var snapshot = SnapshotHelpers.StartResultSnapshot(fieldType); + + var executor = await CreateExecutorAsync(); + var request = + OperationRequestBuilder.New() + .SetDocument($"{{ foo {{ {fieldType} {{ b }} }} }}") + .AddGlobalState("b", null) + .SetErrorHandlingMode(ErrorHandlingMode.Null) + .Build(); + + // act + var result = await executor.ExecuteAsync(request); + + // assert + snapshot.Add(result); + } + + [InlineData("nonnull_prop")] + [InlineData("nullable_prop")] + [Theory] + public async Task Object_NonNullElementHasError_NullMode(string fieldType) + { + // arrange + using var snapshot = SnapshotHelpers.StartResultSnapshot(fieldType); + + var executor = await CreateExecutorAsync(); + + var request = + OperationRequestBuilder.New() + .SetDocument($"{{ foo {{ {fieldType} {{ c }} }} }}") + .AddGlobalState("b", null) + .SetErrorHandlingMode(ErrorHandlingMode.Null) + .Build(); + + // act + var result = await executor.ExecuteAsync(request); + + // assert + snapshot.Add(result); + } + + [InlineData("nullable_list_nullable_element")] + [InlineData("nonnull_list_nullable_element")] + [InlineData("nullable_list_nonnull_element")] + [InlineData("nonnull_list_nonnull_element")] + [Theory] + public async Task List_NonNullElementIsNull_NullMode(string fieldType) + { + // arrange + using var snapshot = SnapshotHelpers.StartResultSnapshot(fieldType); + + var executor = await CreateExecutorAsync(); + + var request = + OperationRequestBuilder.New() + .SetDocument($"{{ foo {{ {fieldType} {{ b }} }} }}") + .AddGlobalState("b", null) + .SetErrorHandlingMode(ErrorHandlingMode.Null) + .Build(); + + // act + var result = await executor.ExecuteAsync(request); + + // assert + snapshot.Add(result); + } + + [InlineData("nullable_list_nullable_element")] + [InlineData("nonnull_list_nullable_element")] + [InlineData("nullable_list_nonnull_element")] + [InlineData("nonnull_list_nonnull_element")] + [Theory] + public async Task List_NonNullElementHasError_NullMode(string fieldType) + { + // arrange + using var snapshot = SnapshotHelpers.StartResultSnapshot(fieldType); + + var executor = await CreateExecutorAsync(); + + var request = + OperationRequestBuilder.New() + .SetDocument($"{{ foo {{ {fieldType} {{ c }} }} }}") + .AddGlobalState("b", null) + .SetErrorHandlingMode(ErrorHandlingMode.Null) + .Build(); + + // act + var result = await executor.ExecuteAsync(request); + + // assert + snapshot.Add(result); + } + + [Fact] + public async Task DefaultErrorHandlingMode_AppliesFromSchemaOptions() + { + // arrange + using var snapshot = SnapshotHelpers.StartResultSnapshot(); + + var executor = await new ServiceCollection() + .AddGraphQL() + .AddDocumentFromString(SchemaText) + .ModifyOptions(o => o.DefaultErrorHandlingMode = ErrorHandlingMode.Null) + .AddResolver("Query", "foo", _ => new(new object())) + .AddResolver("Foo", "nullable_list_nullable_element", _ => new(new[] { new object() })) + .AddResolver("Foo", "nonnull_list_nullable_element", _ => new(new[] { new object() })) + .AddResolver("Foo", "nullable_list_nonnull_element", _ => new(new[] { new object() })) + .AddResolver("Foo", "nonnull_list_nonnull_element", _ => new(new[] { new object() })) + .AddResolver("Foo", "nonnull_prop", _ => new(new object())) + .AddResolver("Foo", "nullable_prop", _ => new(new object())) + .AddResolver("Bar", "a", c => new(c.GetGlobalStateOrDefault("a"))) + .AddResolver("Bar", "b", c => new(c.GetGlobalStateOrDefault("b"))) + .AddResolver("Bar", "c", _ => throw new GraphQLException("ERROR")) + .BuildRequestExecutorAsync(); + + var request = + OperationRequestBuilder.New() + .SetDocument("{ foo { nonnull_prop { b } } }") + .AddGlobalState("b", null) + .Build(); + + // act + var result = await executor.ExecuteAsync(request); + + // assert + snapshot.Add(result); + } + + [Fact] + public async Task PerRequestOverride_OverridesSchemaDefault() + { + // arrange + using var snapshot = SnapshotHelpers.StartResultSnapshot(); + + // Server configured with Propagate (default), but request specifies Null + var executor = await CreateExecutorAsync(); + + var request = + OperationRequestBuilder.New() + .SetDocument("{ foo { nonnull_prop { b } } }") + .AddGlobalState("b", null) + .SetErrorHandlingMode(ErrorHandlingMode.Null) + .Build(); + + // act + var result = await executor.ExecuteAsync(request); + + // assert + snapshot.Add(result); + } + + private const string SchemaText = + """ + type Query { + foo: Foo + } + + type Foo { + nullable_list_nullable_element: [Bar] + nonnull_list_nullable_element: [Bar]! + nullable_list_nonnull_element: [Bar!] + nonnull_list_nonnull_element: [Bar!]! + nonnull_prop: Bar! + nullable_prop: Bar + } + + type Bar { + a: String + b: String! + c: String! + } + """; + + private static async Task CreateExecutorAsync() + { return await new ServiceCollection() .AddGraphQL() - .AddDocumentFromString(schema) + .AddDocumentFromString(SchemaText) .AddResolver("Query", "foo", _ => new(new object())) .AddResolver("Foo", "nullable_list_nullable_element", _ => new(new[] { new object() })) .AddResolver("Foo", "nonnull_list_nullable_element", _ => new(new[] { new object() })) diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.DefaultErrorHandlingMode_AppliesFromSchemaOptions.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.DefaultErrorHandlingMode_AppliesFromSchemaOptions.json new file mode 100644 index 00000000000..2e33161e552 --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.DefaultErrorHandlingMode_AppliesFromSchemaOptions.json @@ -0,0 +1,22 @@ +{ + "errors": [ + { + "message": "Cannot return null for non-nullable field.", + "path": [ + "foo", + "nonnull_prop", + "b" + ], + "extensions": { + "code": "HC0018" + } + } + ], + "data": { + "foo": { + "nonnull_prop": { + "b": null + } + } + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_NullMode_nonnull_list_nonnull_element.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_NullMode_nonnull_list_nonnull_element.json new file mode 100644 index 00000000000..46880d293e0 --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_NullMode_nonnull_list_nonnull_element.json @@ -0,0 +1,22 @@ +{ + "errors": [ + { + "message": "ERROR", + "path": [ + "foo", + "nonnull_list_nonnull_element", + 0, + "c" + ] + } + ], + "data": { + "foo": { + "nonnull_list_nonnull_element": [ + { + "c": null + } + ] + } + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_NullMode_nonnull_list_nullable_element.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_NullMode_nonnull_list_nullable_element.json new file mode 100644 index 00000000000..2c7a4699614 --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_NullMode_nonnull_list_nullable_element.json @@ -0,0 +1,22 @@ +{ + "errors": [ + { + "message": "ERROR", + "path": [ + "foo", + "nonnull_list_nullable_element", + 0, + "c" + ] + } + ], + "data": { + "foo": { + "nonnull_list_nullable_element": [ + { + "c": null + } + ] + } + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_NullMode_nullable_list_nonnull_element.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_NullMode_nullable_list_nonnull_element.json new file mode 100644 index 00000000000..39ae16e0467 --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_NullMode_nullable_list_nonnull_element.json @@ -0,0 +1,22 @@ +{ + "errors": [ + { + "message": "ERROR", + "path": [ + "foo", + "nullable_list_nonnull_element", + 0, + "c" + ] + } + ], + "data": { + "foo": { + "nullable_list_nonnull_element": [ + { + "c": null + } + ] + } + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_NullMode_nullable_list_nullable_element.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_NullMode_nullable_list_nullable_element.json new file mode 100644 index 00000000000..de96ec58d8a --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_NullMode_nullable_list_nullable_element.json @@ -0,0 +1,22 @@ +{ + "errors": [ + { + "message": "ERROR", + "path": [ + "foo", + "nullable_list_nullable_element", + 0, + "c" + ] + } + ], + "data": { + "foo": { + "nullable_list_nullable_element": [ + { + "c": null + } + ] + } + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_NullMode_nonnull_list_nonnull_element.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_NullMode_nonnull_list_nonnull_element.json new file mode 100644 index 00000000000..9513fed1eb1 --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_NullMode_nonnull_list_nonnull_element.json @@ -0,0 +1,25 @@ +{ + "errors": [ + { + "message": "Cannot return null for non-nullable field.", + "path": [ + "foo", + "nonnull_list_nonnull_element", + 0, + "b" + ], + "extensions": { + "code": "HC0018" + } + } + ], + "data": { + "foo": { + "nonnull_list_nonnull_element": [ + { + "b": null + } + ] + } + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_NullMode_nonnull_list_nullable_element.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_NullMode_nonnull_list_nullable_element.json new file mode 100644 index 00000000000..68eb27688be --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_NullMode_nonnull_list_nullable_element.json @@ -0,0 +1,25 @@ +{ + "errors": [ + { + "message": "Cannot return null for non-nullable field.", + "path": [ + "foo", + "nonnull_list_nullable_element", + 0, + "b" + ], + "extensions": { + "code": "HC0018" + } + } + ], + "data": { + "foo": { + "nonnull_list_nullable_element": [ + { + "b": null + } + ] + } + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_NullMode_nullable_list_nonnull_element.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_NullMode_nullable_list_nonnull_element.json new file mode 100644 index 00000000000..882064373c3 --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_NullMode_nullable_list_nonnull_element.json @@ -0,0 +1,25 @@ +{ + "errors": [ + { + "message": "Cannot return null for non-nullable field.", + "path": [ + "foo", + "nullable_list_nonnull_element", + 0, + "b" + ], + "extensions": { + "code": "HC0018" + } + } + ], + "data": { + "foo": { + "nullable_list_nonnull_element": [ + { + "b": null + } + ] + } + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_NullMode_nullable_list_nullable_element.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_NullMode_nullable_list_nullable_element.json new file mode 100644 index 00000000000..5ea169e9e6b --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_NullMode_nullable_list_nullable_element.json @@ -0,0 +1,25 @@ +{ + "errors": [ + { + "message": "Cannot return null for non-nullable field.", + "path": [ + "foo", + "nullable_list_nullable_element", + 0, + "b" + ], + "extensions": { + "code": "HC0018" + } + } + ], + "data": { + "foo": { + "nullable_list_nullable_element": [ + { + "b": null + } + ] + } + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementHasError_NullMode_nonnull_prop.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementHasError_NullMode_nonnull_prop.json new file mode 100644 index 00000000000..14470cc494d --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementHasError_NullMode_nonnull_prop.json @@ -0,0 +1,19 @@ +{ + "errors": [ + { + "message": "ERROR", + "path": [ + "foo", + "nonnull_prop", + "c" + ] + } + ], + "data": { + "foo": { + "nonnull_prop": { + "c": null + } + } + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementHasError_NullMode_nullable_prop.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementHasError_NullMode_nullable_prop.json new file mode 100644 index 00000000000..eecebf5f11f --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementHasError_NullMode_nullable_prop.json @@ -0,0 +1,19 @@ +{ + "errors": [ + { + "message": "ERROR", + "path": [ + "foo", + "nullable_prop", + "c" + ] + } + ], + "data": { + "foo": { + "nullable_prop": { + "c": null + } + } + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementIsNull_NullMode_nonnull_prop.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementIsNull_NullMode_nonnull_prop.json new file mode 100644 index 00000000000..2e33161e552 --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementIsNull_NullMode_nonnull_prop.json @@ -0,0 +1,22 @@ +{ + "errors": [ + { + "message": "Cannot return null for non-nullable field.", + "path": [ + "foo", + "nonnull_prop", + "b" + ], + "extensions": { + "code": "HC0018" + } + } + ], + "data": { + "foo": { + "nonnull_prop": { + "b": null + } + } + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementIsNull_NullMode_nullable_prop.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementIsNull_NullMode_nullable_prop.json new file mode 100644 index 00000000000..75b281e7ff9 --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementIsNull_NullMode_nullable_prop.json @@ -0,0 +1,22 @@ +{ + "errors": [ + { + "message": "Cannot return null for non-nullable field.", + "path": [ + "foo", + "nullable_prop", + "b" + ], + "extensions": { + "code": "HC0018" + } + } + ], + "data": { + "foo": { + "nullable_prop": { + "b": null + } + } + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.PerRequestOverride_OverridesSchemaDefault.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.PerRequestOverride_OverridesSchemaDefault.json new file mode 100644 index 00000000000..2e33161e552 --- /dev/null +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.PerRequestOverride_OverridesSchemaDefault.json @@ -0,0 +1,22 @@ +{ + "errors": [ + { + "message": "Cannot return null for non-nullable field.", + "path": [ + "foo", + "nonnull_prop", + "b" + ], + "extensions": { + "code": "HC0018" + } + } + ], + "data": { + "foo": { + "nonnull_prop": { + "b": null + } + } + } +} diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Results/ValueCompletion.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Results/ValueCompletion.cs index 86202ddf340..622db8ec3ac 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Results/ValueCompletion.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Results/ValueCompletion.cs @@ -17,8 +17,7 @@ internal sealed class ValueCompletion private readonly ISchemaDefinition _schema; private readonly IErrorHandler _errorHandler; private readonly ErrorHandlingMode _errorHandlingMode; - private readonly bool _haltOnError; - private readonly bool _haltOnNullViolation; + private readonly bool _propagateNullValues; private readonly int _maxDepth; public ValueCompletion( @@ -34,8 +33,7 @@ public ValueCompletion( _schema = schema; _errorHandler = errorHandler; _errorHandlingMode = errorHandlingMode; - _haltOnError = errorHandlingMode is ErrorHandlingMode.Halt; - _haltOnNullViolation = errorHandlingMode is ErrorHandlingMode.Propagate or ErrorHandlingMode.Halt; + _propagateNullValues = errorHandlingMode is not ErrorHandlingMode.Null; _maxDepth = maxDepth; } @@ -118,8 +116,6 @@ public bool BuildResult( return ApplyPocketedErrors(target); - case ErrorHandlingMode.Halt: - return false; } } } @@ -332,9 +328,6 @@ private bool ApplyFieldError( switch (_errorHandlingMode) { - case ErrorHandlingMode.Halt: - return false; - case ErrorHandlingMode.Propagate when selection.Type.Kind is TypeKind.NonNull: var didPropagateToRoot = PropagateNullValues(fieldResult); return !didPropagateToRoot; @@ -412,7 +405,7 @@ private bool TryCompleteValue( _store.AddError(error); - return !_haltOnNullViolation; + return !_propagateNullValues; } type = type.InnerType(); @@ -446,11 +439,6 @@ private bool TryCompleteValue( errorWithPath = _errorHandler.Handle(errorWithPath); _store.AddError(errorWithPath); - - if (_haltOnError) - { - return false; - } } else { @@ -542,17 +530,12 @@ private bool TryCompleteList( errorWithPath = _errorHandler.Handle(errorWithPath); _store.AddError(errorWithPath); - - if (_haltOnError) - { - return false; - } } var elementValueKind = element.ValueKind; if (elementValueKind is JsonValueKind.Null or JsonValueKind.Undefined) { - if (isNonNull && _haltOnNullViolation) + if (isNonNull && _propagateNullValues) { return false; } diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/CancellationTests.cs b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/CancellationTests.cs index 0938f74eb70..1dc940cda7f 100644 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/CancellationTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/CancellationTests.cs @@ -46,89 +46,6 @@ public async Task Request_Is_Running_Into_Execution_Timeout_While_Http_Request_I await MatchSnapshotAsync(gateway, request, result); } - [Fact] - public async Task Execution_Is_Halted_While_Http_Request_In_Node_Is_Still_Ongoing() - { - // arrange - using var server1 = CreateSourceSchema( - "A", - b => b - .AddQueryType(), - isTimingOut: true); - - using var server2 = CreateSourceSchema( - "B", - b => b - .AddQueryType()); - - using var gateway = await CreateCompositeSchemaAsync( - [ - ("A", server1), - ("B", server2) - ], - configureGatewayBuilder: builder => - builder.ModifyOptions(o => o.DefaultErrorHandlingMode = ErrorHandlingMode.Halt)); - - using var client = GraphQLHttpClient.Create(gateway.CreateClient()); - - var request = new OperationRequest( - """ - { - topProduct { - id - } - reviews { - id - } - } - """); - - // act - using var result = await client.PostAsync( - request, - new Uri("http://localhost:5000/graphql")); - - // assert - await MatchSnapshotAsync(gateway, request, result); - } - - [Fact] - public async Task Execution_Is_Halted_While_Subscription_Is_Still_Ongoing() - { - // arrange - using var server1 = CreateSourceSchema( - "A", - b => b - .AddQueryType() - .AddSubscriptionType()); - - using var gateway = await CreateCompositeSchemaAsync( - [ - ("A", server1) - ], - configureGatewayBuilder: builder => - builder.ModifyOptions(o => o.DefaultErrorHandlingMode = ErrorHandlingMode.Halt)); - - using var client = GraphQLHttpClient.Create(gateway.CreateClient()); - - var request = new OperationRequest( - """ - subscription { - onReviewCreated { - id - } - } - """); - - // act - using var result = await client.PostAsync( - request, - new Uri("http://localhost:5000/graphql")); - - // assert - await MatchSnapshotAsync(gateway, request, result); - } - [Fact] public async Task Http_Request_To_Source_Schema_Hits_HttpClient_Timeout() { @@ -165,41 +82,6 @@ public async Task Http_Request_To_Source_Schema_Hits_HttpClient_Timeout() await MatchSnapshotAsync(gateway, request, result); } - [Fact] - public async Task Default_ErrorHandlingMode_Can_Be_Changed() - { - // arrange - using var server1 = CreateSourceSchema( - "A", - b => b.AddQueryType()); - - using var gateway = await CreateCompositeSchemaAsync( - [ - ("A", server1) - ], - configureGatewayBuilder: builder => builder - .ModifyOptions(o => o.DefaultErrorHandlingMode = ErrorHandlingMode.Halt)); - - var request = new OperationRequest( - """ - { - reviews { - id - } - } - """); - - // act - using var client = GraphQLHttpClient.Create(gateway.CreateClient()); - - using var result = await client.PostAsync( - request, - new Uri("http://localhost:5000/graphql")); - - // assert - await MatchSnapshotAsync(gateway, request, result); - } - public sealed class SourceSchema1 { public class Query diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/SourceSchemaErrorTests.cs b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/SourceSchemaErrorTests.cs index b02c9ad5c08..f0d4efd1e20 100644 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/SourceSchemaErrorTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/SourceSchemaErrorTests.cs @@ -15,7 +15,6 @@ public class SourceSchemaErrorTests : FusionTestBase [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task Error_On_Root_Field(ErrorHandlingMode onError) { // arrange @@ -49,10 +48,44 @@ public async Task Error_On_Root_Field(ErrorHandlingMode onError) await MatchSnapshotAsync(gateway, request, result, postFix: "OnError_" + onError); } + [Fact] + public async Task SchemaDefault_Null_AppliesWithoutPerRequestOverride() + { + // arrange + using var server1 = CreateSourceSchema( + "A", + b => b.AddQueryType()); + + using var gateway = await CreateCompositeSchemaAsync( + [ + ("A", server1) + ], + configureGatewayBuilder: builder => + builder.ModifyOptions(o => o.DefaultErrorHandlingMode = ErrorHandlingMode.Null)); + + // act — no per-request onError override + using var client = GraphQLHttpClient.Create(gateway.CreateClient()); + + var request = new OperationRequest( + """ + { + productById(id: 1) { + name + } + } + """); + + using var result = await client.PostAsync( + request, + new Uri("http://localhost:5000/graphql")); + + // assert + await MatchSnapshotAsync(gateway, request, result); + } + [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task Error_On_Root_Leaf(ErrorHandlingMode onError) { // arrange @@ -89,7 +122,6 @@ public async Task Error_On_Root_Leaf(ErrorHandlingMode onError) [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task No_Data_And_Error_With_Path_For_Root_Field_NonNull(ErrorHandlingMode onError) { // arrange @@ -126,7 +158,6 @@ public async Task No_Data_And_Error_With_Path_For_Root_Field_NonNull(ErrorHandli [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task No_Data_And_Error_Without_Path_For_Root_Field(ErrorHandlingMode onError) { // arrange @@ -178,7 +209,6 @@ public async Task No_Data_And_Error_Without_Path_For_Root_Field(ErrorHandlingMod [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task No_Data_And_Error_Without_Path_For_Root_Field_NonNull(ErrorHandlingMode onError) { // arrange @@ -230,7 +260,6 @@ public async Task No_Data_And_Error_Without_Path_For_Root_Field_NonNull(ErrorHan [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task SourceSchema_Request_Fails_For_Root_Field(ErrorHandlingMode onError) { // arrange @@ -268,7 +297,6 @@ public async Task SourceSchema_Request_Fails_For_Root_Field(ErrorHandlingMode on [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task SourceSchema_Request_Fails_For_Root_Field_NonNull(ErrorHandlingMode onError) { // arrange @@ -310,7 +338,6 @@ public async Task SourceSchema_Request_Fails_For_Root_Field_NonNull(ErrorHandlin [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task Error_On_Lookup_Leaf(ErrorHandlingMode onError) { // arrange @@ -353,7 +380,6 @@ public async Task Error_On_Lookup_Leaf(ErrorHandlingMode onError) [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task Error_On_Lookup_Field(ErrorHandlingMode onError) { // arrange @@ -396,7 +422,6 @@ public async Task Error_On_Lookup_Field(ErrorHandlingMode onError) [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task Error_On_Lookup_Leaf_NonNull(ErrorHandlingMode onError) { // arrange @@ -439,7 +464,6 @@ public async Task Error_On_Lookup_Leaf_NonNull(ErrorHandlingMode onError) [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task Error_On_Lookup_Field_In_List(ErrorHandlingMode onError) { // arrange @@ -482,7 +506,6 @@ public async Task Error_On_Lookup_Field_In_List(ErrorHandlingMode onError) [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task Error_On_Lookup_Leaf_In_List(ErrorHandlingMode onError) { // arrange @@ -525,7 +548,6 @@ public async Task Error_On_Lookup_Leaf_In_List(ErrorHandlingMode onError) [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task Error_On_Lookup_Leaf_In_List_NonNull(ErrorHandlingMode onError) { // arrange @@ -568,7 +590,6 @@ public async Task Error_On_Lookup_Leaf_In_List_NonNull(ErrorHandlingMode onError [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task No_Data_And_Error_With_Path_For_Lookup_Field_NonNull(ErrorHandlingMode onError) { // arrange @@ -611,7 +632,6 @@ public async Task No_Data_And_Error_With_Path_For_Lookup_Field_NonNull(ErrorHand [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull(ErrorHandlingMode onError) { // arrange @@ -654,7 +674,6 @@ public async Task No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull(ErrorHandl [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task No_Data_And_Error_Without_Path_For_Lookup_Field_NonNull(ErrorHandlingMode onError) { // arrange @@ -712,7 +731,6 @@ public async Task No_Data_And_Error_Without_Path_For_Lookup_Field_NonNull(ErrorH [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task SourceSchema_Request_Fails_For_Lookup(ErrorHandlingMode onError) { // arrange @@ -756,7 +774,6 @@ public async Task SourceSchema_Request_Fails_For_Lookup(ErrorHandlingMode onErro [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task SourceSchema_Request_Fails_For_Lookup_NonNull(ErrorHandlingMode onError) { // arrange @@ -800,7 +817,6 @@ public async Task SourceSchema_Request_Fails_For_Lookup_NonNull(ErrorHandlingMod [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task SourceSchema_Request_Fails_For_Lookup_On_List(ErrorHandlingMode onError) { // arrange @@ -844,7 +860,6 @@ public async Task SourceSchema_Request_Fails_For_Lookup_On_List(ErrorHandlingMod [Theory] [InlineData(ErrorHandlingMode.Propagate)] [InlineData(ErrorHandlingMode.Null)] - [InlineData(ErrorHandlingMode.Halt)] public async Task SourceSchema_Request_Fails_For_Lookup_On_List_NonNull(ErrorHandlingMode onError) { // arrange diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Default_ErrorHandlingMode_Can_Be_Changed.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Default_ErrorHandlingMode_Can_Be_Changed.yaml deleted file mode 100644 index 8e090582311..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Default_ErrorHandlingMode_Can_Be_Changed.yaml +++ /dev/null @@ -1,79 +0,0 @@ -title: Default_ErrorHandlingMode_Can_Be_Changed -request: - document: | - { - reviews { - id - } - } -response: - body: | - { - "errors": [ - { - "message": "Could not resolve reviews", - "path": [ - "reviews" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Query { - reviews: [Review!] - } - - type Review { - id: Int! - } - interactions: - - request: - document: | - query Op_ef4ed803_1 { - reviews { - id - } - } - response: - results: - - | - { - "errors": [ - { - "message": "Could not resolve reviews", - "path": [ - "reviews" - ] - } - ], - "data": { - "reviews": null - } - } -operationPlan: - operation: - - document: | - { - reviews { - id - } - } - hash: ef4ed8030ea8e8d1331adb3822f96a9c - searchSpace: 1 - expandedNodes: 1 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_ef4ed803_1 { - reviews { - id - } - } diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Execution_Is_Halted_While_Http_Request_In_Node_Is_Still_Ongoing.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Execution_Is_Halted_While_Http_Request_In_Node_Is_Still_Ongoing.yaml deleted file mode 100644 index 306013b20a0..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Execution_Is_Halted_While_Http_Request_In_Node_Is_Still_Ongoing.yaml +++ /dev/null @@ -1,116 +0,0 @@ -title: Execution_Is_Halted_While_Http_Request_In_Node_Is_Still_Ongoing -request: - document: | - { - topProduct { - id - } - reviews { - id - } - } -response: - body: | - { - "errors": [ - { - "message": "Could not resolve reviews", - "path": [ - "reviews" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - id: Int! - } - - type Query { - topProduct: Product - } - isTimingOut: true - interactions: - - request: - document: | - query Op_512ba6dc_1 { - topProduct { - id - } - } - - name: B - schema: | - schema { - query: Query - } - - type Query { - reviews: [Review!] - } - - type Review { - id: Int! - } - interactions: - - request: - document: | - query Op_512ba6dc_2 { - reviews { - id - } - } - response: - results: - - | - { - "errors": [ - { - "message": "Could not resolve reviews", - "path": [ - "reviews" - ] - } - ], - "data": { - "reviews": null - } - } -operationPlan: - operation: - - document: | - { - topProduct { - id - } - reviews { - id - } - } - hash: 512ba6dc13ede1ded2da8cd00532a486 - searchSpace: 2 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_512ba6dc_1 { - topProduct { - id - } - } - - id: 2 - type: Operation - schema: B - operation: | - query Op_512ba6dc_2 { - reviews { - id - } - } diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Execution_Is_Halted_While_Subscription_Is_Still_Ongoing.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Execution_Is_Halted_While_Subscription_Is_Still_Ongoing.yaml deleted file mode 100644 index cb344053578..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Execution_Is_Halted_While_Subscription_Is_Still_Ongoing.yaml +++ /dev/null @@ -1,101 +0,0 @@ -title: Execution_Is_Halted_While_Subscription_Is_Still_Ongoing -request: - document: | - subscription { - onReviewCreated { - id - } - } -responseStream: - - body: | - { - "data": { - "onReviewCreated": { - "id": 1 - } - } - } - - body: | - { - "errors": [ - { - "message": "Could not produce review", - "path": [ - "onReviewCreated" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - subscription: Subscription - } - - type Query { - reviews: [Review!] - } - - type Review { - id: Int! - } - - type Subscription { - onReviewCreated: Review - } - interactions: - - request: - document: | - subscription Op_1c7b790e_1 { - onReviewCreated { - id - } - } - response: - contentType: application/jsonl; charset=utf-8 - results: - - | - { - "data": { - "onReviewCreated": { - "id": 1 - } - } - } - - | - { - "errors": [ - { - "message": "Could not produce review", - "path": [ - "onReviewCreated" - ] - } - ], - "data": { - "onReviewCreated": null - } - } -operationPlan: - operation: - - document: | - subscription { - onReviewCreated { - id - } - } - hash: 1c7b790e223d28e348d3e04a33527c96 - searchSpace: 1 - expandedNodes: 1 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - subscription Op_1c7b790e_1 { - onReviewCreated { - id - } - } diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_In_List_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_In_List_OnError_Halt.yaml deleted file mode 100644 index bcbbc586388..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_In_List_OnError_Halt.yaml +++ /dev/null @@ -1,196 +0,0 @@ -title: Error_On_Lookup_Field_In_List -request: - onError: Halt - document: | - { - topProducts { - price - name - } - } -response: - body: | - { - "errors": [ - { - "message": "Could not resolve Product", - "path": [ - "topProducts", - 0, - "name" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - id: Int! - price: Float! - } - - type Query { - topProduct: Product! - nullableTopProduct: Product - topProducts: [Product!]! - productById(id: Int!): Product @lookup @internal - } - interactions: - - request: - document: | - query Op_67b3f75a_1 { - topProducts { - price - id - } - } - response: - results: - - | - { - "data": { - "topProducts": [ - { - "price": 13.99, - "id": 1 - }, - { - "price": 13.99, - "id": 2 - }, - { - "price": 13.99, - "id": 3 - } - ] - } - } - - name: B - schema: | - schema { - query: Query - } - - type Product { - name: String - id: Int! - } - - type Query { - productById(id: Int!): Product @lookup - } - interactions: - - request: - document: | - query Op_67b3f75a_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - variables: | - [ - { - "__fusion_1_id": 1 - }, - { - "__fusion_1_id": 2 - }, - { - "__fusion_1_id": 3 - } - ] - response: - contentType: application/jsonl; charset=utf-8 - results: - - | - { - "errors": [ - { - "message": "Could not resolve Product", - "path": [ - "productById" - ] - } - ], - "data": { - "productById": null - } - } - - | - { - "errors": [ - { - "message": "Could not resolve Product", - "path": [ - "productById" - ] - } - ], - "data": { - "productById": null - } - } - - | - { - "errors": [ - { - "message": "Could not resolve Product", - "path": [ - "productById" - ] - } - ], - "data": { - "productById": null - } - } -operationPlan: - operation: - - document: | - { - topProducts { - price - name - id @fusion__requirement - } - } - hash: 67b3f75afa8d6eb979605a59d5462c1d - searchSpace: 1 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_67b3f75a_1 { - topProducts { - price - id - } - } - - id: 2 - type: Operation - schema: B - operation: | - query Op_67b3f75a_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - source: $.productById - target: $.topProducts - requirements: - - name: __fusion_1_id - selectionMap: >- - id - dependencies: - - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_OnError_Halt.yaml deleted file mode 100644 index 254c4929f8a..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_OnError_Halt.yaml +++ /dev/null @@ -1,148 +0,0 @@ -title: Error_On_Lookup_Field -request: - onError: Halt - document: | - { - topProduct { - price - name - } - } -response: - body: | - { - "errors": [ - { - "message": "Could not resolve Product", - "path": [ - "topProduct", - "name" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - id: Int! - price: Float! - } - - type Query { - topProduct: Product! - nullableTopProduct: Product - topProducts: [Product!]! - productById(id: Int!): Product @lookup @internal - } - interactions: - - request: - document: | - query Op_e24d93b6_1 { - topProduct { - price - id - } - } - response: - results: - - | - { - "data": { - "topProduct": { - "price": 13.99, - "id": 1 - } - } - } - - name: B - schema: | - schema { - query: Query - } - - type Product { - name: String - id: Int! - } - - type Query { - productById(id: Int!): Product @lookup - } - interactions: - - request: - document: | - query Op_e24d93b6_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - variables: | - { - "__fusion_1_id": 1 - } - response: - results: - - | - { - "errors": [ - { - "message": "Could not resolve Product", - "path": [ - "productById" - ] - } - ], - "data": { - "productById": null - } - } -operationPlan: - operation: - - document: | - { - topProduct { - price - name - id @fusion__requirement - } - } - hash: e24d93b6245cedd878fff4452f5f16b9 - searchSpace: 1 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_e24d93b6_1 { - topProduct { - price - id - } - } - - id: 2 - type: Operation - schema: B - operation: | - query Op_e24d93b6_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - source: $.productById - target: $.topProduct - requirements: - - name: __fusion_1_id - selectionMap: >- - id - dependencies: - - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_NonNull_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_NonNull_OnError_Halt.yaml deleted file mode 100644 index fdf6ce7c33e..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_NonNull_OnError_Halt.yaml +++ /dev/null @@ -1,196 +0,0 @@ -title: Error_On_Lookup_Leaf_In_List_NonNull -request: - onError: Halt - document: | - { - topProducts { - price - name - } - } -response: - body: | - { - "errors": [ - { - "message": "Could not resolve Product", - "path": [ - "topProducts", - 0, - "name" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - id: Int! - price: Float! - } - - type Query { - topProduct: Product! - nullableTopProduct: Product - topProducts: [Product!]! - productById(id: Int!): Product @lookup @internal - } - interactions: - - request: - document: | - query Op_67b3f75a_1 { - topProducts { - price - id - } - } - response: - results: - - | - { - "data": { - "topProducts": [ - { - "price": 13.99, - "id": 1 - }, - { - "price": 13.99, - "id": 2 - }, - { - "price": 13.99, - "id": 3 - } - ] - } - } - - name: B - schema: | - schema { - query: Query - } - - type Product { - name: String! - id: Int! - } - - type Query { - productById(id: Int!): Product @lookup - } - interactions: - - request: - document: | - query Op_67b3f75a_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - variables: | - [ - { - "__fusion_1_id": 1 - }, - { - "__fusion_1_id": 2 - }, - { - "__fusion_1_id": 3 - } - ] - response: - contentType: application/jsonl; charset=utf-8 - results: - - | - { - "errors": [ - { - "message": "Could not resolve Product", - "path": [ - "productById" - ] - } - ], - "data": { - "productById": null - } - } - - | - { - "errors": [ - { - "message": "Could not resolve Product", - "path": [ - "productById" - ] - } - ], - "data": { - "productById": null - } - } - - | - { - "errors": [ - { - "message": "Could not resolve Product", - "path": [ - "productById" - ] - } - ], - "data": { - "productById": null - } - } -operationPlan: - operation: - - document: | - { - topProducts { - price - name - id @fusion__requirement - } - } - hash: 67b3f75afa8d6eb979605a59d5462c1d - searchSpace: 1 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_67b3f75a_1 { - topProducts { - price - id - } - } - - id: 2 - type: Operation - schema: B - operation: | - query Op_67b3f75a_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - source: $.productById - target: $.topProducts - requirements: - - name: __fusion_1_id - selectionMap: >- - id - dependencies: - - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_OnError_Halt.yaml deleted file mode 100644 index 63792a255e4..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_OnError_Halt.yaml +++ /dev/null @@ -1,205 +0,0 @@ -title: Error_On_Lookup_Leaf_In_List -request: - onError: Halt - document: | - { - topProducts { - price - name - } - } -response: - body: | - { - "errors": [ - { - "message": "Could not resolve Product.name", - "path": [ - "topProducts", - 0, - "name" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - id: Int! - price: Float! - } - - type Query { - topProduct: Product! - nullableTopProduct: Product - topProducts: [Product!]! - productById(id: Int!): Product @lookup @internal - } - interactions: - - request: - document: | - query Op_67b3f75a_1 { - topProducts { - price - id - } - } - response: - results: - - | - { - "data": { - "topProducts": [ - { - "price": 13.99, - "id": 1 - }, - { - "price": 13.99, - "id": 2 - }, - { - "price": 13.99, - "id": 3 - } - ] - } - } - - name: B - schema: | - schema { - query: Query - } - - type Product { - name: String - id: Int! - } - - type Query { - productById(id: Int!): Product @lookup - } - interactions: - - request: - document: | - query Op_67b3f75a_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - variables: | - [ - { - "__fusion_1_id": 1 - }, - { - "__fusion_1_id": 2 - }, - { - "__fusion_1_id": 3 - } - ] - response: - contentType: application/jsonl; charset=utf-8 - results: - - | - { - "errors": [ - { - "message": "Could not resolve Product.name", - "path": [ - "productById", - "name" - ] - } - ], - "data": { - "productById": { - "name": null - } - } - } - - | - { - "errors": [ - { - "message": "Could not resolve Product.name", - "path": [ - "productById", - "name" - ] - } - ], - "data": { - "productById": { - "name": null - } - } - } - - | - { - "errors": [ - { - "message": "Could not resolve Product.name", - "path": [ - "productById", - "name" - ] - } - ], - "data": { - "productById": { - "name": null - } - } - } -operationPlan: - operation: - - document: | - { - topProducts { - price - name - id @fusion__requirement - } - } - hash: 67b3f75afa8d6eb979605a59d5462c1d - searchSpace: 1 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_67b3f75a_1 { - topProducts { - price - id - } - } - - id: 2 - type: Operation - schema: B - operation: | - query Op_67b3f75a_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - source: $.productById - target: $.topProducts - requirements: - - name: __fusion_1_id - selectionMap: >- - id - dependencies: - - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_NonNull_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_NonNull_OnError_Halt.yaml deleted file mode 100644 index 967f0e18f1d..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_NonNull_OnError_Halt.yaml +++ /dev/null @@ -1,148 +0,0 @@ -title: Error_On_Lookup_Leaf_NonNull -request: - onError: Halt - document: | - { - topProduct { - price - name - } - } -response: - body: | - { - "errors": [ - { - "message": "Could not resolve Product", - "path": [ - "topProduct", - "name" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - id: Int! - price: Float! - } - - type Query { - topProduct: Product! - nullableTopProduct: Product - topProducts: [Product!]! - productById(id: Int!): Product @lookup @internal - } - interactions: - - request: - document: | - query Op_e24d93b6_1 { - topProduct { - price - id - } - } - response: - results: - - | - { - "data": { - "topProduct": { - "price": 13.99, - "id": 1 - } - } - } - - name: B - schema: | - schema { - query: Query - } - - type Product { - name: String! - id: Int! - } - - type Query { - productById(id: Int!): Product @lookup - } - interactions: - - request: - document: | - query Op_e24d93b6_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - variables: | - { - "__fusion_1_id": 1 - } - response: - results: - - | - { - "errors": [ - { - "message": "Could not resolve Product", - "path": [ - "productById" - ] - } - ], - "data": { - "productById": null - } - } -operationPlan: - operation: - - document: | - { - topProduct { - price - name - id @fusion__requirement - } - } - hash: e24d93b6245cedd878fff4452f5f16b9 - searchSpace: 1 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_e24d93b6_1 { - topProduct { - price - id - } - } - - id: 2 - type: Operation - schema: B - operation: | - query Op_e24d93b6_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - source: $.productById - target: $.topProduct - requirements: - - name: __fusion_1_id - selectionMap: >- - id - dependencies: - - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_OnError_Halt.yaml deleted file mode 100644 index 0daa0ed0b57..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_OnError_Halt.yaml +++ /dev/null @@ -1,151 +0,0 @@ -title: Error_On_Lookup_Leaf -request: - onError: Halt - document: | - { - topProduct { - price - name - } - } -response: - body: | - { - "errors": [ - { - "message": "Could not resolve Product.name", - "path": [ - "topProduct", - "name" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - id: Int! - price: Float! - } - - type Query { - topProduct: Product! - nullableTopProduct: Product - topProducts: [Product!]! - productById(id: Int!): Product @lookup @internal - } - interactions: - - request: - document: | - query Op_e24d93b6_1 { - topProduct { - price - id - } - } - response: - results: - - | - { - "data": { - "topProduct": { - "price": 13.99, - "id": 1 - } - } - } - - name: B - schema: | - schema { - query: Query - } - - type Product { - name: String - id: Int! - } - - type Query { - productById(id: Int!): Product @lookup - } - interactions: - - request: - document: | - query Op_e24d93b6_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - variables: | - { - "__fusion_1_id": 1 - } - response: - results: - - | - { - "errors": [ - { - "message": "Could not resolve Product.name", - "path": [ - "productById", - "name" - ] - } - ], - "data": { - "productById": { - "name": null - } - } - } -operationPlan: - operation: - - document: | - { - topProduct { - price - name - id @fusion__requirement - } - } - hash: e24d93b6245cedd878fff4452f5f16b9 - searchSpace: 1 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_e24d93b6_1 { - topProduct { - price - id - } - } - - id: 2 - type: Operation - schema: B - operation: | - query Op_e24d93b6_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - source: $.productById - target: $.topProduct - requirements: - - name: __fusion_1_id - selectionMap: >- - id - dependencies: - - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Leaf_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Leaf_OnError_Halt.yaml deleted file mode 100644 index d776c666f0a..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Leaf_OnError_Halt.yaml +++ /dev/null @@ -1,85 +0,0 @@ -title: Error_On_Root_Leaf -request: - onError: Halt - document: | - { - productById(id: 1) { - name - } - } -response: - body: | - { - "errors": [ - { - "message": "Could not resolve Product.name", - "path": [ - "productById", - "name" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - name: String - id: Int! - } - - type Query { - productById(id: Int!): Product @lookup - } - interactions: - - request: - document: | - query Op_97fd38fc_1 { - productById(id: 1) { - name - } - } - response: - results: - - | - { - "errors": [ - { - "message": "Could not resolve Product.name", - "path": [ - "productById", - "name" - ] - } - ], - "data": { - "productById": { - "name": null - } - } - } -operationPlan: - operation: - - document: | - { - productById(id: 1) { - name - } - } - hash: 97fd38fcea394bc6badd7ea22c6de660 - searchSpace: 1 - expandedNodes: 1 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_97fd38fc_1 { - productById(id: 1) { - name - } - } diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Field_NonNull_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Field_NonNull_OnError_Halt.yaml deleted file mode 100644 index 89a938ed424..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Field_NonNull_OnError_Halt.yaml +++ /dev/null @@ -1,146 +0,0 @@ -title: No_Data_And_Error_With_Path_For_Lookup_Field_NonNull -request: - onError: Halt - document: | - { - topProduct { - price - name - } - } -response: - body: | - { - "errors": [ - { - "message": "Could not resolve Product", - "path": [ - "topProduct", - "name" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - id: Int! - price: Float! - } - - type Query { - topProduct: Product! - nullableTopProduct: Product - topProducts: [Product!]! - productById(id: Int!): Product @lookup @internal - } - interactions: - - request: - document: | - query Op_e24d93b6_1 { - topProduct { - price - id - } - } - response: - results: - - | - { - "data": { - "topProduct": { - "price": 13.99, - "id": 1 - } - } - } - - name: B - schema: | - schema { - query: Query - } - - type Product { - name: String! - id: Int! - } - - type Query { - productById(id: Int!): Product! @lookup - } - interactions: - - request: - document: | - query Op_e24d93b6_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - variables: | - { - "__fusion_1_id": 1 - } - response: - results: - - | - { - "errors": [ - { - "message": "Could not resolve Product", - "path": [ - "productById" - ] - } - ], - "data": null - } -operationPlan: - operation: - - document: | - { - topProduct { - price - name - id @fusion__requirement - } - } - hash: e24d93b6245cedd878fff4452f5f16b9 - searchSpace: 1 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_e24d93b6_1 { - topProduct { - price - id - } - } - - id: 2 - type: Operation - schema: B - operation: | - query Op_e24d93b6_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - source: $.productById - target: $.topProduct - requirements: - - name: __fusion_1_id - selectionMap: >- - id - dependencies: - - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull_OnError_Halt.yaml deleted file mode 100644 index bb5458435e8..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull_OnError_Halt.yaml +++ /dev/null @@ -1,147 +0,0 @@ -title: No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull -request: - onError: Halt - document: | - { - topProduct { - price - name - } - } -response: - body: | - { - "errors": [ - { - "message": "Could not resolve Product.name", - "path": [ - "topProduct", - "name" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - id: Int! - price: Float! - } - - type Query { - topProduct: Product! - nullableTopProduct: Product - topProducts: [Product!]! - productById(id: Int!): Product @lookup @internal - } - interactions: - - request: - document: | - query Op_e24d93b6_1 { - topProduct { - price - id - } - } - response: - results: - - | - { - "data": { - "topProduct": { - "price": 13.99, - "id": 1 - } - } - } - - name: B - schema: | - schema { - query: Query - } - - type Product { - name: String! - id: Int! - } - - type Query { - productById(id: Int!): Product! @lookup - } - interactions: - - request: - document: | - query Op_e24d93b6_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - variables: | - { - "__fusion_1_id": 1 - } - response: - results: - - | - { - "errors": [ - { - "message": "Could not resolve Product.name", - "path": [ - "productById", - "name" - ] - } - ], - "data": null - } -operationPlan: - operation: - - document: | - { - topProduct { - price - name - id @fusion__requirement - } - } - hash: e24d93b6245cedd878fff4452f5f16b9 - searchSpace: 1 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_e24d93b6_1 { - topProduct { - price - id - } - } - - id: 2 - type: Operation - schema: B - operation: | - query Op_e24d93b6_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - source: $.productById - target: $.topProduct - requirements: - - name: __fusion_1_id - selectionMap: >- - id - dependencies: - - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Root_Field_NonNull_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Root_Field_NonNull_OnError_Halt.yaml deleted file mode 100644 index 3381500bd30..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Root_Field_NonNull_OnError_Halt.yaml +++ /dev/null @@ -1,79 +0,0 @@ -title: No_Data_And_Error_With_Path_For_Root_Field_NonNull -request: - onError: Halt - document: | - { - productById(id: 1) { - name - } - } -response: - body: | - { - "errors": [ - { - "message": "Could not resolve Product", - "path": [ - "productById" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - name: String! - id: Int! - } - - type Query { - productById(id: Int!): Product! @lookup - } - interactions: - - request: - document: | - query Op_97fd38fc_1 { - productById(id: 1) { - name - } - } - response: - results: - - | - { - "errors": [ - { - "message": "Could not resolve Product", - "path": [ - "productById" - ] - } - ], - "data": null - } -operationPlan: - operation: - - document: | - { - productById(id: 1) { - name - } - } - hash: 97fd38fcea394bc6badd7ea22c6de660 - searchSpace: 1 - expandedNodes: 1 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_97fd38fc_1 { - productById(id: 1) { - name - } - } diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_Without_Path_For_Lookup_Field_NonNull_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_Without_Path_For_Lookup_Field_NonNull_OnError_Halt.yaml deleted file mode 100644 index b680c4a5451..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_Without_Path_For_Lookup_Field_NonNull_OnError_Halt.yaml +++ /dev/null @@ -1,146 +0,0 @@ -title: No_Data_And_Error_Without_Path_For_Lookup_Field_NonNull -request: - onError: Halt - document: | - { - topProduct { - price - name - } - } -response: - body: | - { - "errors": [ - { - "message": "A global error" - }, - { - "message": "Unexpected Execution Error", - "path": [ - "topProduct", - "name" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - id: Int! - price: Float! - } - - type Query { - topProduct: Product! - nullableTopProduct: Product - topProducts: [Product!]! - productById(id: Int!): Product @lookup @internal - } - interactions: - - request: - document: | - query Op_e24d93b6_1 { - topProduct { - price - id - } - } - response: - results: - - | - { - "data": { - "topProduct": { - "price": 13.99, - "id": 1 - } - } - } - - name: B - schema: | - schema { - query: Query - } - - type Product { - name: String! - id: Int! - } - - type Query { - productById(id: Int!): Product @lookup - } - interactions: - - request: - document: | - query Op_e24d93b6_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - variables: | - { - "__fusion_1_id": 1 - } - response: - statusCode: 400 - results: - - | - { - "errors": [ - { - "message": "A global error" - } - ] - } -operationPlan: - operation: - - document: | - { - topProduct { - price - name - id @fusion__requirement - } - } - hash: e24d93b6245cedd878fff4452f5f16b9 - searchSpace: 1 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_e24d93b6_1 { - topProduct { - price - id - } - } - - id: 2 - type: Operation - schema: B - operation: | - query Op_e24d93b6_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - source: $.productById - target: $.topProduct - requirements: - - name: __fusion_1_id - selectionMap: >- - id - dependencies: - - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_Without_Path_For_Root_Field_NonNull_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_Without_Path_For_Root_Field_NonNull_OnError_Halt.yaml deleted file mode 100644 index e5d8b4929cd..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_Without_Path_For_Root_Field_NonNull_OnError_Halt.yaml +++ /dev/null @@ -1,79 +0,0 @@ -title: No_Data_And_Error_Without_Path_For_Root_Field_NonNull -request: - onError: Halt - document: | - { - productById(id: 1) { - name - } - } -response: - body: | - { - "errors": [ - { - "message": "A global error" - }, - { - "message": "Unexpected Execution Error", - "path": [ - "productById" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - name: String! - id: Int! - } - - type Query { - productById(id: Int!): Product! @lookup - } - interactions: - - request: - document: | - query Op_97fd38fc_1 { - productById(id: 1) { - name - } - } - response: - statusCode: 400 - results: - - | - { - "errors": [ - { - "message": "A global error" - } - ] - } -operationPlan: - operation: - - document: | - { - productById(id: 1) { - name - } - } - hash: 97fd38fcea394bc6badd7ea22c6de660 - searchSpace: 1 - expandedNodes: 1 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_97fd38fc_1 { - productById(id: 1) { - name - } - } diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_Without_Path_For_Root_Field_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_Without_Path_For_Root_Field_OnError_Halt.yaml deleted file mode 100644 index 5e5a4a37e82..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_Without_Path_For_Root_Field_OnError_Halt.yaml +++ /dev/null @@ -1,79 +0,0 @@ -title: No_Data_And_Error_Without_Path_For_Root_Field -request: - onError: Halt - document: | - { - productById(id: 1) { - name - } - } -response: - body: | - { - "errors": [ - { - "message": "A global error" - }, - { - "message": "Unexpected Execution Error", - "path": [ - "productById" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - name: String! - id: Int! - } - - type Query { - productById(id: Int!): Product @lookup - } - interactions: - - request: - document: | - query Op_97fd38fc_1 { - productById(id: 1) { - name - } - } - response: - statusCode: 400 - results: - - | - { - "errors": [ - { - "message": "A global error" - } - ] - } -operationPlan: - operation: - - document: | - { - productById(id: 1) { - name - } - } - hash: 97fd38fcea394bc6badd7ea22c6de660 - searchSpace: 1 - expandedNodes: 1 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_97fd38fc_1 { - productById(id: 1) { - name - } - } diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Field_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SchemaDefault_Null_AppliesWithoutPerRequestOverride.yaml similarity index 92% rename from src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Field_OnError_Halt.yaml rename to src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SchemaDefault_Null_AppliesWithoutPerRequestOverride.yaml index 1e9f0d0b0ba..2206b7feac0 100644 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Field_OnError_Halt.yaml +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SchemaDefault_Null_AppliesWithoutPerRequestOverride.yaml @@ -1,6 +1,5 @@ -title: Error_On_Root_Field +title: SchemaDefault_Null_AppliesWithoutPerRequestOverride request: - onError: Halt document: | { productById(id: 1) { @@ -10,6 +9,9 @@ request: response: body: | { + "data": { + "productById": null + }, "errors": [ { "message": "Could not resolve Product", diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Lookup_NonNull_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Lookup_NonNull_OnError_Halt.yaml deleted file mode 100644 index b0fa19101a3..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Lookup_NonNull_OnError_Halt.yaml +++ /dev/null @@ -1,134 +0,0 @@ -title: SourceSchema_Request_Fails_For_Lookup_NonNull -request: - onError: Halt - document: | - { - topProduct { - price - name - } - } -response: - body: | - { - "errors": [ - { - "message": "Unexpected Execution Error", - "path": [ - "topProduct", - "name" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - id: Int! - price: Float! - } - - type Query { - topProduct: Product! - nullableTopProduct: Product - topProducts: [Product!]! - productById(id: Int!): Product @lookup @internal - } - interactions: - - request: - document: | - query Op_e24d93b6_1 { - topProduct { - price - id - } - } - response: - results: - - | - { - "data": { - "topProduct": { - "price": 13.99, - "id": 1 - } - } - } - - name: B - schema: | - schema { - query: Query - } - - type Product { - name: String! - id: Int! - } - - type Query { - productById(id: Int!): Product @lookup - } - interactions: - - request: - document: | - query Op_e24d93b6_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - variables: | - { - "__fusion_1_id": 1 - } - response: - statusCode: 500 -operationPlan: - operation: - - document: | - { - topProduct { - price - name - id @fusion__requirement - } - } - hash: e24d93b6245cedd878fff4452f5f16b9 - searchSpace: 1 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_e24d93b6_1 { - topProduct { - price - id - } - } - - id: 2 - type: Operation - schema: B - operation: | - query Op_e24d93b6_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - source: $.productById - target: $.topProduct - requirements: - - name: __fusion_1_id - selectionMap: >- - id - dependencies: - - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Lookup_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Lookup_OnError_Halt.yaml deleted file mode 100644 index 80e0746ba48..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Lookup_OnError_Halt.yaml +++ /dev/null @@ -1,134 +0,0 @@ -title: SourceSchema_Request_Fails_For_Lookup -request: - onError: Halt - document: | - { - nullableTopProduct { - price - name - } - } -response: - body: | - { - "errors": [ - { - "message": "Unexpected Execution Error", - "path": [ - "nullableTopProduct", - "name" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - id: Int! - price: Float! - } - - type Query { - topProduct: Product! - nullableTopProduct: Product - topProducts: [Product!]! - productById(id: Int!): Product @lookup @internal - } - interactions: - - request: - document: | - query Op_12015865_1 { - nullableTopProduct { - price - id - } - } - response: - results: - - | - { - "data": { - "nullableTopProduct": { - "price": 13.99, - "id": 1 - } - } - } - - name: B - schema: | - schema { - query: Query - } - - type Product { - name: String - id: Int! - } - - type Query { - productById(id: Int!): Product @lookup - } - interactions: - - request: - document: | - query Op_12015865_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - variables: | - { - "__fusion_1_id": 1 - } - response: - statusCode: 500 -operationPlan: - operation: - - document: | - { - nullableTopProduct { - price - name - id @fusion__requirement - } - } - hash: 12015865a78f4ab2330778c5486a4026 - searchSpace: 1 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_12015865_1 { - nullableTopProduct { - price - id - } - } - - id: 2 - type: Operation - schema: B - operation: | - query Op_12015865_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - source: $.productById - target: $.nullableTopProduct - requirements: - - name: __fusion_1_id - selectionMap: >- - id - dependencies: - - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Lookup_On_List_NonNull_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Lookup_On_List_NonNull_OnError_Halt.yaml deleted file mode 100644 index 4a70b7a3081..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Lookup_On_List_NonNull_OnError_Halt.yaml +++ /dev/null @@ -1,153 +0,0 @@ -title: SourceSchema_Request_Fails_For_Lookup_On_List_NonNull -request: - onError: Halt - document: | - { - topProducts { - price - name - } - } -response: - body: | - { - "errors": [ - { - "message": "Unexpected Execution Error", - "path": [ - "topProducts", - 0, - "name" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - id: Int! - price: Float! - } - - type Query { - topProduct: Product! - nullableTopProduct: Product - topProducts: [Product!]! - productById(id: Int!): Product @lookup @internal - } - interactions: - - request: - document: | - query Op_67b3f75a_1 { - topProducts { - price - id - } - } - response: - results: - - | - { - "data": { - "topProducts": [ - { - "price": 13.99, - "id": 1 - }, - { - "price": 13.99, - "id": 2 - }, - { - "price": 13.99, - "id": 3 - } - ] - } - } - - name: B - schema: | - schema { - query: Query - } - - type Product { - name: String! - id: Int! - } - - type Query { - productById(id: Int!): Product @lookup - } - interactions: - - request: - document: | - query Op_67b3f75a_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - variables: | - [ - { - "__fusion_1_id": 1 - }, - { - "__fusion_1_id": 2 - }, - { - "__fusion_1_id": 3 - } - ] - response: - statusCode: 500 -operationPlan: - operation: - - document: | - { - topProducts { - price - name - id @fusion__requirement - } - } - hash: 67b3f75afa8d6eb979605a59d5462c1d - searchSpace: 1 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_67b3f75a_1 { - topProducts { - price - id - } - } - - id: 2 - type: Operation - schema: B - operation: | - query Op_67b3f75a_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - source: $.productById - target: $.topProducts - requirements: - - name: __fusion_1_id - selectionMap: >- - id - dependencies: - - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Lookup_On_List_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Lookup_On_List_OnError_Halt.yaml deleted file mode 100644 index 21e2505a121..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Lookup_On_List_OnError_Halt.yaml +++ /dev/null @@ -1,153 +0,0 @@ -title: SourceSchema_Request_Fails_For_Lookup_On_List -request: - onError: Halt - document: | - { - topProducts { - price - name - } - } -response: - body: | - { - "errors": [ - { - "message": "Unexpected Execution Error", - "path": [ - "topProducts", - 0, - "name" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - id: Int! - price: Float! - } - - type Query { - topProduct: Product! - nullableTopProduct: Product - topProducts: [Product!]! - productById(id: Int!): Product @lookup @internal - } - interactions: - - request: - document: | - query Op_67b3f75a_1 { - topProducts { - price - id - } - } - response: - results: - - | - { - "data": { - "topProducts": [ - { - "price": 13.99, - "id": 1 - }, - { - "price": 13.99, - "id": 2 - }, - { - "price": 13.99, - "id": 3 - } - ] - } - } - - name: B - schema: | - schema { - query: Query - } - - type Product { - name: String - id: Int! - } - - type Query { - productById(id: Int!): Product @lookup - } - interactions: - - request: - document: | - query Op_67b3f75a_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - variables: | - [ - { - "__fusion_1_id": 1 - }, - { - "__fusion_1_id": 2 - }, - { - "__fusion_1_id": 3 - } - ] - response: - statusCode: 500 -operationPlan: - operation: - - document: | - { - topProducts { - price - name - id @fusion__requirement - } - } - hash: 67b3f75afa8d6eb979605a59d5462c1d - searchSpace: 1 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_67b3f75a_1 { - topProducts { - price - id - } - } - - id: 2 - type: Operation - schema: B - operation: | - query Op_67b3f75a_2( - $__fusion_1_id: Int! - ) { - productById(id: $__fusion_1_id) { - name - } - } - source: $.productById - target: $.topProducts - requirements: - - name: __fusion_1_id - selectionMap: >- - id - dependencies: - - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Root_Field_NonNull_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Root_Field_NonNull_OnError_Halt.yaml deleted file mode 100644 index 0f9cdf97106..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Root_Field_NonNull_OnError_Halt.yaml +++ /dev/null @@ -1,70 +0,0 @@ -title: SourceSchema_Request_Fails_For_Root_Field_NonNull -request: - onError: Halt - document: | - { - topProduct { - price - } - } -response: - body: | - { - "errors": [ - { - "message": "Unexpected Execution Error", - "path": [ - "topProduct" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - id: Int! - price: Float! - } - - type Query { - topProduct: Product! - nullableTopProduct: Product - topProducts: [Product!]! - productById(id: Int!): Product @lookup @internal - } - interactions: - - request: - document: | - query Op_1c1cf024_1 { - topProduct { - price - } - } - response: - statusCode: 500 -operationPlan: - operation: - - document: | - { - topProduct { - price - } - } - hash: 1c1cf0244bcda9f7f91e7e0becca0616 - searchSpace: 1 - expandedNodes: 1 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_1c1cf024_1 { - topProduct { - price - } - } diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Root_Field_OnError_Halt.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Root_Field_OnError_Halt.yaml deleted file mode 100644 index 7f26f9e3c7a..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.SourceSchema_Request_Fails_For_Root_Field_OnError_Halt.yaml +++ /dev/null @@ -1,70 +0,0 @@ -title: SourceSchema_Request_Fails_For_Root_Field -request: - onError: Halt - document: | - { - nullableTopProduct { - price - } - } -response: - body: | - { - "errors": [ - { - "message": "Unexpected Execution Error", - "path": [ - "nullableTopProduct" - ] - } - ] - } -sourceSchemas: - - name: A - schema: | - schema { - query: Query - } - - type Product { - id: Int! - price: Float! - } - - type Query { - topProduct: Product! - nullableTopProduct: Product - topProducts: [Product!]! - productById(id: Int!): Product @lookup @internal - } - interactions: - - request: - document: | - query Op_14c79a43_1 { - nullableTopProduct { - price - } - } - response: - statusCode: 500 -operationPlan: - operation: - - document: | - { - nullableTopProduct { - price - } - } - hash: 14c79a43eb6ce3e1a1fa16337c365654 - searchSpace: 1 - expandedNodes: 1 - nodes: - - id: 1 - type: Operation - schema: A - operation: | - query Op_14c79a43_1 { - nullableTopProduct { - price - } - } diff --git a/src/HotChocolate/Language/src/Language.Web/ErrorHandlingMode.cs b/src/HotChocolate/Language/src/Language.Web/ErrorHandlingMode.cs index 281d6d77e4b..1ff5a7653f6 100644 --- a/src/HotChocolate/Language/src/Language.Web/ErrorHandlingMode.cs +++ b/src/HotChocolate/Language/src/Language.Web/ErrorHandlingMode.cs @@ -3,6 +3,5 @@ namespace HotChocolate.Language; public enum ErrorHandlingMode { Propagate = 0, - Null = 1, - Halt = 2 + Null = 1 } diff --git a/src/HotChocolate/Language/src/Language.Web/Properties/LangWebResources.Designer.cs b/src/HotChocolate/Language/src/Language.Web/Properties/LangWebResources.Designer.cs index 42e5de20c66..70f8b407a73 100644 --- a/src/HotChocolate/Language/src/Language.Web/Properties/LangWebResources.Designer.cs +++ b/src/HotChocolate/Language/src/Language.Web/Properties/LangWebResources.Designer.cs @@ -104,6 +104,12 @@ internal static string ThrowHelper_InvalidOnErrorValue { return ResourceManager.GetString("ThrowHelper_InvalidOnErrorValue", resourceCulture); } } + + internal static string ThrowHelper_UnknownOnErrorValue { + get { + return ResourceManager.GetString("ThrowHelper_UnknownOnErrorValue", resourceCulture); + } + } internal static string Utf8GraphQLRequestParser_Parse_EmptyJSONDocument { get { diff --git a/src/HotChocolate/Language/src/Language.Web/Properties/LangWebResources.resx b/src/HotChocolate/Language/src/Language.Web/Properties/LangWebResources.resx index f989044553e..27a3f8f93e6 100644 --- a/src/HotChocolate/Language/src/Language.Web/Properties/LangWebResources.resx +++ b/src/HotChocolate/Language/src/Language.Web/Properties/LangWebResources.resx @@ -48,6 +48,9 @@ Invalid 'onError' value. Expected string or null, but got {0}. + + Unknown 'onError' value '{0}'. Allowed values are 'PROPAGATE' or 'NULL'. + Empty JSON document. diff --git a/src/HotChocolate/Language/src/Language.Web/ThrowHelper.cs b/src/HotChocolate/Language/src/Language.Web/ThrowHelper.cs index fcbd9f39f72..4f7c6e736a1 100644 --- a/src/HotChocolate/Language/src/Language.Web/ThrowHelper.cs +++ b/src/HotChocolate/Language/src/Language.Web/ThrowHelper.cs @@ -34,6 +34,12 @@ public static InvalidGraphQLRequestException InvalidOnErrorValue(JsonTokenType t ThrowHelper_InvalidOnErrorValue, tokenType)); + public static InvalidGraphQLRequestException UnknownOnErrorValue(string? value) + => new(string.Format( + CultureInfo.InvariantCulture, + ThrowHelper_UnknownOnErrorValue, + value)); + public static InvalidGraphQLRequestException InvalidVariablesValue(JsonTokenType tokenType) => new(string.Format( CultureInfo.InvariantCulture, diff --git a/src/HotChocolate/Language/src/Language.Web/Utf8GraphQLRequestParser.cs b/src/HotChocolate/Language/src/Language.Web/Utf8GraphQLRequestParser.cs index f2cf19074eb..aeea912cef9 100644 --- a/src/HotChocolate/Language/src/Language.Web/Utf8GraphQLRequestParser.cs +++ b/src/HotChocolate/Language/src/Language.Web/Utf8GraphQLRequestParser.cs @@ -253,8 +253,7 @@ private readonly GraphQLRequest ParseRequest(ref Utf8JsonReader reader, Operatio { "PROPAGATE" => ErrorHandlingMode.Propagate, "NULL" => ErrorHandlingMode.Null, - "HALT" => ErrorHandlingMode.Halt, - _ => null + _ => throw ThrowHelper.UnknownOnErrorValue(mode) }; } else if (reader.TokenType == JsonTokenType.Null) diff --git a/src/HotChocolate/Language/test/Language.Web.Tests/Utf8GraphQLRequestParserTests.cs b/src/HotChocolate/Language/test/Language.Web.Tests/Utf8GraphQLRequestParserTests.cs index cba67360c1c..789b00fc776 100644 --- a/src/HotChocolate/Language/test/Language.Web.Tests/Utf8GraphQLRequestParserTests.cs +++ b/src/HotChocolate/Language/test/Language.Web.Tests/Utf8GraphQLRequestParserTests.cs @@ -248,12 +248,9 @@ public void Parse_Id_As_Name() [Theory] [InlineData("PROPAGATE", ErrorHandlingMode.Propagate)] [InlineData("NULL", ErrorHandlingMode.Null)] - [InlineData("HALT", ErrorHandlingMode.Halt)] [InlineData("propagate", ErrorHandlingMode.Propagate)] [InlineData("null", ErrorHandlingMode.Null)] - [InlineData("halt", ErrorHandlingMode.Halt)] [InlineData(null, null)] - [InlineData("bla", null)] public void Parse_OnError(string? onError, ErrorHandlingMode? expectedErrorHandlingMode) { // arrange @@ -1046,6 +1043,18 @@ public void Parse_OperationName_Invalid_Type_Array_Throws() Assert.Contains("operationName", exception.Message, StringComparison.OrdinalIgnoreCase); } + [Fact] + public void Parse_OnError_Unknown_Value_Throws() + { + // arrange + var source = "{\"onError\": \"HALT\", \"query\": \"{ __typename }\"}"u8.ToArray(); + + // act & assert + var exception = Assert.Throws( + () => Utf8GraphQLRequestParser.Parse(source)); + Assert.Contains("onError", exception.Message, StringComparison.OrdinalIgnoreCase); + } + [Fact] public void Parse_OnError_Invalid_Type_Number_Throws() { @@ -1062,7 +1071,7 @@ public void Parse_OnError_Invalid_Type_Number_Throws() public void Parse_OnError_Invalid_Type_Object_Throws() { // arrange - var source = "{\"onError\": {\"mode\": \"HALT\"}, \"query\": \"{ __typename }\"}"u8.ToArray(); + var source = "{\"onError\": {\"mode\": \"NULL\"}, \"query\": \"{ __typename }\"}"u8.ToArray(); // act & assert var exception = Assert.Throws(