ChilliCream / ChilliCream/graphql-platform

Add support for the default interface method implementation

Open
#7,030 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

🌶️ hot chocolate Area: Type System
Dominant language
C#
Stars
5.8k
Forks
810
Avg merge
15h 39m
Merged PRs (30d)
98

Description

Product

Hot Chocolate

Is your feature request related to a problem?

Lets imagine we want the Hot Chocolate to produce a schema like:

interface IChannel {
  id: ID!
  description: String!
  status: ChannelStatus!
}

union IAnotherChannel = ChannelTypeB | ChannelTypeC

type ChannelTypeA implements IChannel {
  id: ID!
  description: String!
  status: ChannelStatus!
  ip: String!
}

type ChannelTypeB implements IChannel {
  id: ID!
  description: String!
  status: ChannelStatus!
  port: String!
}

type ChannelTypeC implements IChannel {
  id: ID!
  description: String!
  status: ChannelStatus!
  adapter: String!
}

I have to use records in my project. So I did somethink like:

[GraphQLName("IChannel")]
public interface IChannelDto
{
    [ID]
    Guid Id { get; init; }

    string Description { get; init; }

    #region workaround
    // TODO: delete after Hot Chocolate Team fixes one of two issue:
    // - ExtendObjectType should extend interface and all derived classes
    // - interface default methods implementations must be used in derived classes
    Task<ChannelStatus> GetStatusAsync() { throw new NotImplementedException(); }
    #endregion
}

[ExtendObjectType(typeof(IChannelDto))]
public class ChannelResolvers
{
    public async Task<ChannelStatus> GetStatusAsync()
    {
        // Do some stuff
    }
}

[GraphQLName("ChannelTypeA")]
public record ChannelTypeADto
(
    [property: ID] Guid Id,
    string Description,
    string IP,
) : IChannelDto;

[UnionType("IAnotherChannel")]
public interface IAnotherChannelDto : IChannelDto { };

[GraphQLName("ChannelTypeB")]
public record ChannelTypeBDto
(
    [property: ID] Guid Id,
    string Description,
    string Port,
) : IAnotherChannelDto;

[GraphQLName("ChannelTypeC")]
public record ChannelTypeCDto
(
    [property: ID] Guid Id,
    string Description,
    string Adapter,
) : IAnotherChannelDto;

Here is a problem:

  1. The ExtendObjectType annotation does not extend interfaces by design but I need it, so I made a workaround. That stub function is never called and I only need it to create the schema.
  2. I can't just remove the class with the ExtendObjectType annotation and put the default implementation inside the interface. Hot chocolate want me to add a Status field inside all derived records.

I must use both the ExtendObjectType annotation and that stub default implementation in the interface. If I could replace records with classes, I would do something like:

[InterfaceType("IChannel")]
public abstract class ChannelDto
{
    [ID]
    public Guid Id { get; init; }

    public string Description { get; init; }

    public async Task<ChannelStatus> GetStatusAsync()
    {
        // Do some stuff
    }
}

[GraphQLName("ChannelTypeA")]
public class ChannelTypeADto : ChannelDto
{
    public string IP { get; init; }
}

[UnionType("IAnotherChannel")]
public abstract class AnotherChannelDto : ChannelDto { };

[GraphQLName("ChannelTypeB")]
public class ChannelTypeBDto : AnotherChannelDto
{
    public string Port { get; init; }
}

[GraphQLName("ChannelTypeC")]
public class ChannelTypeCDto : AnotherChannelDto
{ 
    public string Adapter { get; init; }
}

This works nice!

The solution you'd like

One of:

  1. Let the ExtendObjectType annotation extend interfaces.
  2. Add support for the default method implementation in the schema inference algorithm.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the ExtendObjectType handling and the schema inference algorithm described in the issue. Compare the record/interface example with the working abstract-class example, then determine whether interface extensions or default interface method implementations should be supported. Done means one of the requested behaviors produces the intended schema without the workaround.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, graphql
Domain
api, backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.