Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FieldBindingFlags.Default Error Types Throw SchemaException #7111

Open
PHILLIPS71 opened this issue May 22, 2024 · 2 comments
Open

FieldBindingFlags.Default Error Types Throw SchemaException #7111

PHILLIPS71 opened this issue May 22, 2024 · 2 comments
Labels
🌶️ hot chocolate ❓ question This issue is a question about feature of Hot Chocolate.

Comments

@PHILLIPS71
Copy link
Contributor

PHILLIPS71 commented May 22, 2024

Product

Hot Chocolate

Version

14.0.0-p.100

Link to minimal reproduction

https://github.com/PHILLIPS71/HC-7111

Steps to reproduce

When using the FieldBindingFlags.Default with mutation conventions, error types do not function as expected, despite having object types defined for the exceptions and or errors being thrown.

[MutationType]
public class LibraryMutation
{
    [Error<DomainError>]
    public Library? LibraryCreate(string name)
    {
        throw new DomainException("bad");
    }
}

public class DomainException(string type) : Exception
{
    public string Type { get; } = type;
}

public record DomainError
{
    public string Message => "a domain exception was thrown...";

    public string Type { get; }

    public DomainError(string type)
    {
        Type = type;
    }

    public static DomainError? CreateErrorFrom(DomainException exception)
        => new DomainError(exception.Type);
}

[ObjectType<DomainError>]
public static partial class DomainErrorType
{
    static partial void Configure(IObjectTypeDescriptor<DomainError> descriptor)
    {
        descriptor
            .Field(p => p.Message);

        descriptor
            .Field(p => p.Type);
    }
}

[ObjectType<DomainException>]
public static partial class DomainExceptionType
{
    static partial void Configure(IObjectTypeDescriptor<DomainException> descriptor)
    {
        descriptor
            .Field(p => p.Message);

        descriptor
            .Field(p => p.Type);
    }
}

What is expected?

If exceptions or object types are properly defined and expose the message field, a SchemaException should not occur.

What is actually happening?

It consistently throws a SchemaException, indicating that the exception does not expose a message property.

Relevant log output

fail: Microsoft.AspNetCore.Server.Kestrel[13]
      Connection id "0HN3Q8NUENKE7", Request id "0HN3Q8NUENKE7:00000001": An unhandled exception was thrown by the application.
      HotChocolate.SchemaException: For more details look at the `Errors` property.

      1. For more details look at the `Errors` property.

      1. Error while building type HotChocolate.Types.ErrorObjectType`1[[HC_7111.GraphQL.DomainError, HC_7111, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]. The runtime type HC_7111.GraphQL.DomainError does not define a property named `Message`
       (HotChocolate.Types.ErrorObjectType<HC_7111.GraphQL.DomainError>)

         at HotChocolate.Configuration.TypeInitializer.DiscoverTypes()
         at HotChocolate.Configuration.TypeInitializer.Initialize()
         at HotChocolate.SchemaBuilder.Setup.InitializeTypes(SchemaBuilder builder, IDescriptorContext context, IReadOnlyList`1 types)
         at HotChocolate.SchemaBuilder.Setup.Create(SchemaBuilder builder, LazySchema lazySchema, IDescriptorContext context)
         at HotChocolate.SchemaBuilder.Create(IDescriptorContext context)
         at HotChocolate.SchemaBuilder.HotChocolate.ISchemaBuilder.Create(IDescriptorContext context)
         at HotChocolate.Execution.RequestExecutorResolver.CreateSchemaAsync(ConfigurationContext context, RequestExecutorSetup setup, RequestExecutorOptions executorOptions, IServiceProvider schemaServices, TypeModuleChangeMonitor typeModuleChangeMonitor, CancellationToken cancellationToken)
         at HotChocolate.Execution.RequestExecutorResolver.CreateSchemaServicesAsync(ConfigurationContext context, RequestExecutorSetup setup, CancellationToken cancellationToken)
         at HotChocolate.Execution.RequestExecutorResolver.GetRequestExecutorNoLockAsync(String schemaName, CancellationToken cancellationToken)
         at HotChocolate.Execution.RequestExecutorResolver.GetRequestExecutorAsync(String schemaName, CancellationToken cancellationToken)
         at HotChocolate.Execution.RequestExecutorProxy.GetRequestExecutorAsync(CancellationToken cancellationToken)
         at HotChocolate.AspNetCore.HttpPostMiddlewareBase.HandleRequestAsync(HttpContext context)
         at HotChocolate.AspNetCore.HttpPostMiddlewareBase.InvokeAsync(HttpContext context)
         at Microsoft.AspNetCore.Builder.EndpointRouteBuilderExtensions.<>c__DisplayClass23_0.<<UseCancellation>b__1>d.MoveNext()
      --- End of stack trace from previous location ---
         at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

Additional context

No response

@PHILLIPS71 PHILLIPS71 added the 🐛 bug Something isn't working label May 22, 2024
@michaelstaib
Copy link
Member

This is actually not a bug ... what we do internally is register an error type for mutation convention errors ... this is the ErrorObjectType that you can see.

@michaelstaib michaelstaib added ❓ question This issue is a question about feature of Hot Chocolate. and removed 🐛 bug Something isn't working labels May 28, 2024
@PHILLIPS71
Copy link
Contributor Author

@michaelstaib, thanks for the follow up. You're right when using the code below, it internally registers an error type for the mutation conventions and does not raise any SchemaException.

[MutationType]
public class LibraryMutation
{
    [Error<DomainException>]
    public Library? LibraryCreate(string name)
    {
        throw new DomainException("bad");
    }
}

public class DomainException(string type) : Exception
{
    public string Message => "a domain exception was thrown...";

    public string Type { get; } = type;
}

The issue that now arises is that I am unable to configure which fields I want to expose to the GraphQL layer (or I might be doing it incorrectly). Without configuring the object type extension, it only exposes the Message field, which is expected since it's required for mutation conventions. However, in this case, I also want to expose the DomainException.Type property, which I cannot seem to achieve.

Introducing the following object type configuration does not resolve the issue, as only the Message field continues to be exposed in the schema:

[ObjectType<DomainException>]
public static partial class DomainExceptionType
{
    static partial void Configure(IObjectTypeDescriptor<DomainException> descriptor)
    {
        descriptor
            .Field(p => p.Message);

        descriptor
            .Field(p => p.Type);
    }
}

How can I configure these additional fields on the exceptions so that they are exposed in the GraphQL layer, while still using FieldBindingFlags.Default?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🌶️ hot chocolate ❓ question This issue is a question about feature of Hot Chocolate.
Projects
None yet
Development

No branches or pull requests

2 participants