Skip to content

Commit d0b27e3

Browse files
tobias-tenglermichaelstaib
authored andcommitted
[Fusion] Add IncludeExceptionDetails option (#8694)
1 parent 2e79407 commit d0b27e3

File tree

5 files changed

+56
-16
lines changed

5 files changed

+56
-16
lines changed

src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/FusionRequestExecutorManager.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -302,9 +302,13 @@ private void AddCoreServices(IServiceCollection services, FusionRequestOptions r
302302
services.AddSingleton(static sp => sp.GetRequiredService<RequestExecutorAccessor>().RequestExecutor);
303303
services.AddSingleton<IRequestExecutor>(sp => sp.GetRequiredService<FusionRequestExecutor>());
304304
services.AddSingleton(static sp => sp.GetRequiredService<ISchemaDefinition>().GetRequestOptions());
305-
services.AddSingleton<IErrorHandler>(static sp => new DefaultErrorHandler(sp.GetServices<IErrorFilter>()));
306-
services.AddSingleton<IErrorFilter>(static _ => new AddDebugInformationErrorFilter());
307305
services.TryAddSingleton<INodeIdParser, DefaultNodeIdParser>();
306+
services.AddSingleton<IErrorHandler>(static sp => new DefaultErrorHandler(sp.GetServices<IErrorFilter>()));
307+
308+
if (requestOptions.IncludeExceptionDetails)
309+
{
310+
services.AddSingleton<IErrorFilter>(static _ => new AddDebugInformationErrorFilter());
311+
}
308312

309313
services.AddSingleton(static _ => new SchemaDefinitionAccessor());
310314
services.AddSingleton(static sp => sp.GetRequiredService<SchemaDefinitionAccessor>().Schema);

src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/FusionRequestOptions.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public sealed class FusionRequestOptions : ICloneable
1616
private bool _allowErrorHandlingModeOverride;
1717
private PersistedOperationOptions _persistedOperationOptions = new();
1818
private bool _isReadOnly;
19+
private bool _includeExceptionDetails;
1920

2021
/// <summary>
2122
/// Gets or sets the execution timeout.
@@ -166,6 +167,26 @@ public PersistedOperationOptions PersistedOperations
166167
}
167168
}
168169

170+
/// <summary>
171+
/// Gets or sets whether exception details should be included for GraphQL
172+
/// errors in the GraphQL response.
173+
/// This should only be enabled for development purposes
174+
/// and not in production environments.
175+
/// </summary>
176+
public bool IncludeExceptionDetails
177+
{
178+
get => _includeExceptionDetails;
179+
set
180+
{
181+
if (_isReadOnly)
182+
{
183+
throw new InvalidOperationException("The request options are read-only.");
184+
}
185+
186+
_includeExceptionDetails = value;
187+
}
188+
}
189+
169190
/// <summary>
170191
/// Clones the request options into a new mutable instance.
171192
/// </summary>

src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/OperationPlanContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,11 @@ public OperationPlanContext(
6161
_clientScope = requestContext.CreateClientScope();
6262
_nodeIdParser = requestContext.Schema.Services.GetRequiredService<INodeIdParser>();
6363
_diagnosticEvents = requestContext.Schema.Services.GetRequiredService<IFusionExecutionDiagnosticEvents>();
64+
var errorHandler = requestContext.Schema.Services.GetRequiredService<IErrorHandler>();
6465

6566
_resultStore = new FetchResultStore(
6667
requestContext.Schema,
68+
errorHandler,
6769
_resultPoolSessionHolder,
6870
operationPlan.Operation,
6971
requestContext.ErrorHandlingMode(),

src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Results/FetchResultStore.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Runtime.InteropServices;
66
using System.Text.Json;
77
using HotChocolate.Buffers;
8+
using HotChocolate.Execution;
89
using HotChocolate.Fusion.Execution.Clients;
910
using HotChocolate.Fusion.Execution.Nodes;
1011
using HotChocolate.Fusion.Language;
@@ -18,8 +19,9 @@ internal sealed class FetchResultStore : IDisposable
1819
{
1920
private readonly ReaderWriterLockSlim _lock = new(LockRecursionPolicy.NoRecursion);
2021
private readonly ISchemaDefinition _schema;
22+
private readonly IErrorHandler _errorHandler;
2123
private readonly Operation _operation;
22-
private readonly ErrorHandlingMode _errorHandling;
24+
private readonly ErrorHandlingMode _errorHandlingMode;
2325
private readonly ulong _includeFlags;
2426
private readonly ConcurrentStack<IDisposable> _memory = [];
2527
private ObjectResult _root = null!;
@@ -29,18 +31,20 @@ internal sealed class FetchResultStore : IDisposable
2931

3032
public FetchResultStore(
3133
ISchemaDefinition schema,
34+
IErrorHandler errorHandler,
3235
ResultPoolSession resultPoolSession,
3336
Operation operation,
34-
ErrorHandlingMode errorHandling,
37+
ErrorHandlingMode errorHandlingMode,
3538
ulong includeFlags)
3639
{
3740
ArgumentNullException.ThrowIfNull(schema);
3841
ArgumentNullException.ThrowIfNull(resultPoolSession);
3942
ArgumentNullException.ThrowIfNull(operation);
4043

4144
_schema = schema;
45+
_errorHandler = errorHandler;
4246
_operation = operation;
43-
_errorHandling = errorHandling;
47+
_errorHandlingMode = errorHandlingMode;
4448
_includeFlags = includeFlags;
4549

4650
Reset(resultPoolSession);
@@ -55,8 +59,9 @@ public void Reset(ResultPoolSession resultPoolSession)
5559

5660
_valueCompletion = new ValueCompletion(
5761
_schema,
62+
_errorHandler,
5863
resultPoolSession,
59-
_errorHandling,
64+
_errorHandlingMode,
6065
32,
6166
_includeFlags,
6267
_errors);

src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Results/ValueCompletion.cs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Runtime.CompilerServices;
22
using System.Text.Json;
3+
using HotChocolate.Execution;
34
using HotChocolate.Fusion.Execution.Clients;
45
using HotChocolate.Fusion.Execution.Nodes;
56
using HotChocolate.Language;
@@ -10,16 +11,18 @@ namespace HotChocolate.Fusion.Execution.Results;
1011
internal sealed class ValueCompletion
1112
{
1213
private readonly ISchemaDefinition _schema;
14+
private readonly IErrorHandler _errorHandler;
1315
private readonly ResultPoolSession _resultPoolSession;
14-
private readonly ErrorHandlingMode _errorHandling;
16+
private readonly ErrorHandlingMode _errorHandlingMode;
1517
private readonly int _maxDepth;
1618
private readonly ulong _includeFlags;
1719
private readonly List<IError> _errors;
1820

1921
public ValueCompletion(
2022
ISchemaDefinition schema,
23+
IErrorHandler errorHandler,
2124
ResultPoolSession resultPoolSession,
22-
ErrorHandlingMode errorHandling,
25+
ErrorHandlingMode errorHandlingMode,
2326
int maxDepth,
2427
ulong includeFlags,
2528
List<IError> errors)
@@ -29,8 +32,9 @@ public ValueCompletion(
2932
ArgumentNullException.ThrowIfNull(errors);
3033

3134
_schema = schema;
35+
_errorHandler = errorHandler;
3236
_resultPoolSession = resultPoolSession;
33-
_errorHandling = errorHandling;
37+
_errorHandlingMode = errorHandlingMode;
3438
_maxDepth = maxDepth;
3539
_includeFlags = includeFlags;
3640
_errors = errors;
@@ -80,7 +84,7 @@ public bool BuildResult(
8084

8185
if (!TryCompleteValue(selection, selection.Type, property.Value, errorTrieForResponseName, 0, fieldResult))
8286
{
83-
switch (_errorHandling)
87+
switch (_errorHandlingMode)
8488
{
8589
case ErrorHandlingMode.Propagate:
8690
var didPropagateToRoot = PropagateNullValues(objectResult);
@@ -122,15 +126,16 @@ public bool BuildErrorResult(
122126
.SetPath(path.Append(responseName))
123127
.AddLocation(fieldResult.Selection.SyntaxNodes[0].Node)
124128
.Build();
129+
errorWithPath = _errorHandler.Handle(errorWithPath);
125130

126131
_errors.Add(errorWithPath);
127132

128-
if (_errorHandling is ErrorHandlingMode.Halt)
133+
if (_errorHandlingMode is ErrorHandlingMode.Halt)
129134
{
130135
return false;
131136
}
132137

133-
if (_errorHandling is ErrorHandlingMode.Propagate && fieldResult.Selection.Type.IsNonNullType())
138+
if (_errorHandlingMode is ErrorHandlingMode.Propagate && fieldResult.Selection.Type.IsNonNullType())
134139
{
135140
var didPropagateToRoot = PropagateNullValues(objectResult);
136141

@@ -189,9 +194,10 @@ private bool TryCompleteValue(
189194
.SetPath(parent.Path)
190195
.AddLocation(selection.SyntaxNodes[0].Node)
191196
.Build();
197+
errorWithPath = _errorHandler.Handle(errorWithPath);
192198
_errors.Add(errorWithPath);
193199

194-
if (_errorHandling is ErrorHandlingMode.Halt)
200+
if (_errorHandlingMode is ErrorHandlingMode.Halt)
195201
{
196202
return false;
197203
}
@@ -207,10 +213,11 @@ private bool TryCompleteValue(
207213
.SetPath(parent.Path)
208214
.AddLocation(selection.SyntaxNodes[0].Node)
209215
.Build();
216+
nonNullViolationError = _errorHandler.Handle(nonNullViolationError);
210217

211218
_errors.Add(nonNullViolationError);
212219

213-
if (_errorHandling is ErrorHandlingMode.Propagate or ErrorHandlingMode.Halt)
220+
if (_errorHandlingMode is ErrorHandlingMode.Propagate or ErrorHandlingMode.Halt)
214221
{
215222
return false;
216223
}
@@ -284,17 +291,18 @@ private bool TryCompleteList(
284291
.SetPath(parent.Path.Append(i))
285292
.AddLocation(selection.SyntaxNodes[0].Node)
286293
.Build();
294+
errorWithPath = _errorHandler.Handle(errorWithPath);
287295
_errors.Add(errorWithPath);
288296

289-
if (_errorHandling is ErrorHandlingMode.Halt)
297+
if (_errorHandlingMode is ErrorHandlingMode.Halt)
290298
{
291299
return false;
292300
}
293301
}
294302

295303
if (item.IsNullOrUndefined())
296304
{
297-
if (!isNullable && _errorHandling is ErrorHandlingMode.Propagate or ErrorHandlingMode.Halt)
305+
if (!isNullable && _errorHandlingMode is ErrorHandlingMode.Propagate or ErrorHandlingMode.Halt)
298306
{
299307
return false;
300308
}

0 commit comments

Comments
 (0)