Skip to content

Commit

Permalink
Added Schema Error Interceptor (#2581)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib committed Nov 27, 2020
1 parent 421c765 commit 28f8695
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using HotChocolate;
using HotChocolate.Configuration;
using HotChocolate.Execution.Configuration;
using HotChocolate.Types.Descriptors;
using HotChocolate.Types.Descriptors.Definitions;

namespace Microsoft.Extensions.DependencyInjection
Expand Down Expand Up @@ -356,10 +357,30 @@ public static partial class SchemaRequestExecutorBuilderExtensions
throw new ArgumentNullException(nameof(onAfterCompleteType));
}

return builder.ConfigureSchema(b => b
.TryAddTypeInterceptor(new DelegateTypeInitializationInterceptor<T>(
canHandle,
onAfterCompleteType: onAfterCompleteType)));
return builder.ConfigureSchema(
b => b.TryAddTypeInterceptor(
new DelegateTypeInitializationInterceptor<T>(
canHandle,
onAfterCompleteType: onAfterCompleteType)));
}

public static IRequestExecutorBuilder OnSchemaError(
this IRequestExecutorBuilder builder,
Action<IDescriptorContext, Exception> onError)
{
if (builder is null)
{
throw new ArgumentNullException(nameof(builder));
}

if (onError is null)
{
throw new ArgumentNullException(nameof(onError));
}

return builder.ConfigureSchema(
b => b.TryAddSchemaInterceptor(
new DelegateSchemaInterceptor(onError: onError)));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,18 @@ public void OnAfterCreate(IDescriptorContext context, ISchema schema)
interceptor.OnAfterCreate(context, schema);
}
}

public void OnError(IDescriptorContext context, Exception exception)
{
if (_interceptors.Count == 0)
{
return;
}

foreach (ISchemaInterceptor interceptor in _interceptors)
{
interceptor.OnError(context, exception);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using HotChocolate.Types.Descriptors;

#nullable enable

namespace HotChocolate.Configuration
{
public class DelegateSchemaInterceptor : SchemaInterceptor
{
private readonly Action<IDescriptorContext, ISchemaBuilder>? _onBeforeCreate;
private readonly Action<IDescriptorContext, ISchema>? _onAfterCreate;
private readonly Action<IDescriptorContext, Exception>? _onError;

public DelegateSchemaInterceptor(
Action<IDescriptorContext, ISchemaBuilder>? onBeforeCreate = null,
Action<IDescriptorContext, ISchema>? onAfterCreate = null,
Action<IDescriptorContext, Exception>? onError = null)
{
_onAfterCreate = onAfterCreate;
_onBeforeCreate = onBeforeCreate;
_onError = onError;
}

public override void OnBeforeCreate(
IDescriptorContext context,
ISchemaBuilder schemaBuilder) =>
_onBeforeCreate?.Invoke(context, schemaBuilder);

public override void OnAfterCreate(
IDescriptorContext context,
ISchema schema) =>
_onAfterCreate?.Invoke(context, schema);

public override void OnError(
IDescriptorContext context,
Exception exception) =>
_onError?.Invoke(context, exception);
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using HotChocolate.Types.Descriptors;

namespace HotChocolate.Configuration
Expand All @@ -7,5 +8,7 @@ public interface ISchemaInterceptor
void OnBeforeCreate(IDescriptorContext context, ISchemaBuilder schemaBuilder);

void OnAfterCreate(IDescriptorContext context, ISchema schema);

void OnError(IDescriptorContext context, Exception exception);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System;
using HotChocolate.Types.Descriptors;

#nullable enable

namespace HotChocolate.Configuration
{
public class SchemaInterceptor : ISchemaInterceptor
Expand All @@ -19,5 +22,11 @@ protected SchemaInterceptor()
ISchema schema)
{
}

public virtual void OnError(
IDescriptorContext context,
Exception exception)
{
}
}
}
22 changes: 16 additions & 6 deletions src/HotChocolate/Core/src/Types/SchemaBuilder.Setup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,25 @@ public static Schema Create(SchemaBuilder builder)
{
var lazySchema = new LazySchema();
DescriptorContext context = CreateContext(builder, lazySchema);
IBindingLookup bindingLookup = builder._bindingCompiler.Compile(context);

IReadOnlyList<ITypeReference> typeReferences =
CreateTypeReferences(builder, context, bindingLookup);
try
{
IBindingLookup bindingLookup = builder._bindingCompiler.Compile(context);

IReadOnlyList<ITypeReference> typeReferences =
CreateTypeReferences(builder, context, bindingLookup);

TypeRegistry typeRegistry =
InitializeTypes(builder, context, bindingLookup, typeReferences, lazySchema);
TypeRegistry typeRegistry =
InitializeTypes(builder, context, bindingLookup, typeReferences,
lazySchema);

return CompleteSchema(builder, context, lazySchema, typeRegistry);
return CompleteSchema(builder, context, lazySchema, typeRegistry);
}
catch (Exception ex)
{
context.SchemaInterceptor.OnError(context, ex);
throw;
}
}

private static DescriptorContext CreateContext(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using System;
using System.Threading.Tasks;
using HotChocolate.Execution.Configuration;
using HotChocolate.Types;
using HotChocolate.Types.Descriptors.Definitions;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Snapshooter.Xunit;
using Xunit;
using static HotChocolate.Tests.TestHelper;
Expand Down Expand Up @@ -669,5 +672,50 @@ public async Task OnAfterCompleteType_Generic_CanHandle()
Assert.True(found);
Assert.True(canHandleInvoked);
}

[Fact]
public async Task OnSchemaError()
{
// arrange
Snapshot.FullName();
Exception ex = null;

// act
try
{
await new ServiceCollection()
.AddGraphQL()
.OnSchemaError((_, exception) => ex = exception)
.BuildSchemaAsync();
}
catch
{
// ignored
}

// assert
Assert.IsType<SchemaException>(ex);
}

[Fact]
public void OnSchemaError_Builder_IsNull()
{
void Action() =>
SchemaRequestExecutorBuilderExtensions
.OnSchemaError(null!, (context, exception) => { });

Assert.Throws<ArgumentNullException>(Action);
}

[Fact]
public void OnSchemaError_OnError_IsNull()
{
var builder = new Mock<IRequestExecutorBuilder>();

void Action() =>
builder.Object.OnSchemaError(null!);

Assert.Throws<ArgumentNullException>(Action);
}
}
}
31 changes: 31 additions & 0 deletions src/HotChocolate/Core/test/Types.Tests/SchemaErrorTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using HotChocolate.Configuration;
using HotChocolate.Language;
using HotChocolate.Types;
using HotChocolate.Types.Descriptors;
using Xunit;

namespace HotChocolate
Expand Down Expand Up @@ -129,5 +132,33 @@ public void CreateSchemaError_AddSyntaxNode()
Assert.Null(schemaError.Path);
Assert.Null(schemaError.Code);
}

[Fact]
public void Intercept_Schema_Error()
{
// arrange
var errorInterceptor = new ErrorInterceptor();

// act
void Action() => SchemaBuilder.New()
.TryAddSchemaInterceptor(errorInterceptor)
.Create();

// assert
Assert.Throws<SchemaException>(Action);
Assert.Collection(
errorInterceptor.Exceptions,
ex => Assert.IsType<SchemaException>(ex));
}

private class ErrorInterceptor : SchemaInterceptor
{
public List<Exception> Exceptions { get; } = new List<Exception>();

public override void OnError(IDescriptorContext context, Exception exception)
{
Exceptions.Add(exception);
}
}
}
}

0 comments on commit 28f8695

Please sign in to comment.