graphql-platform icon indicating copy to clipboard operation
graphql-platform copied to clipboard

Support Default Interface Implementations(Traits) for SchemaBuilding

Open mastorm opened this issue 2 years ago • 2 comments

Is your feature request related to a problem?

Given the following Type

public class Example : TenantEntity
{
    public string Message { get; set; }
}

(TenantEntity contains a Guid Id)

If we want to use the Relay Node feature, we need to specify an explicit resolver on every Node-Type like this:

[Node]
public class Example : TenantEntity
{
    public string Message { get; set; }
    
    [Authorize]
    public static Task<Example> GetAsync(Guid id, DataLoaderById<Example> loader) => loader.LoadAsync(id);
}

This leads to a lot of code duplication, since we need to do this for all the types we have.

The solution you'd like

A neat solution to this would be a default interface implementation. Those can be used as Traits like this:

interface IResolvable<T> where T: Entity
{    
    [Authorize]
    static Task<T> GetAsync(Guid id, DataLoaderById<T> loader) => loader.LoadAsync(id);
}

Sadly, using this approach ends up in an exception at the moment:

System.ArgumentNullException: Value cannot be null. (Parameter 'method')
   at HotChocolate.Types.Relay.Descriptors.NodeDescriptorBase.ResolveNodeWith(MethodInfo method)
   at HotChocolate.Types.Relay.Descriptors.NodeDescriptor.ResolveNode(Type type)
   at HotChocolate.Types.Relay.NodeAttribute.<>c__DisplayClass12_0.<OnConfigure>b__1(ITypeCompletionContext descriptorContext, ObjectTypeDefinition definition)
   at HotChocolate.Types.Descriptors.DescriptorBase`1.<>c__DisplayClass25_0.<OnBeforeCompletion>b__0(ITypeCompletionContext c, IDefinition d)
   at HotChocolate.Types.TypeSystemObjectBase`1.ExecuteConfigurations(ITypeCompletionContext context, TDefinition definition, ApplyConfigurationOn on)
   at HotChocolate.Types.TypeSystemObjectBase`1.CompleteType(ITypeCompletionContext context)
   at HotChocolate.Configuration.TypeInitializer.<CompleteTypes>g__CompleteType|27_0(RegisteredType registeredType)
   at HotChocolate.Configuration.TypeInitializer.ProcessTypes(TypeDependencyKind kind, Func`2 action)
   at HotChocolate.Configuration.TypeInitializer.CompleteTypes()
   at HotChocolate.Configuration.TypeInitializer.Initialize()

The introduction of trait support could seriously simplify(or even remove) a lot of tedious boilerplate we have to write at the moment. An example of how the Example-Type would look like with that trait:

[Node]
public class Example : TenantEntity, IResolvable<Notification>
{
    public string Message { get; set; }
}

Product

Hot Chocolate

mastorm avatar Mar 15 '22 07:03 mastorm