graphqlhotchocolategraphql-federation

How to get HotChocolate to decorate object types with key directive?


Given the object:

public class Parent
{
    public Parent(string id, string name)
    {
        Id = id;
        Name = name;
    }

    [Key]
    [ID]
    public string Id { get; }

    public string Name { get; }

    [ReferenceResolver]
    public static Parent? Get(ParentRepository repository, string id)
    {
        return repository.GetParent(id);
    }
}

I get the following graphql schema:

type Parent {
  id: ID!
  name: String!
}

But expect this:

type Parent @key(fields: "id") {
  id: ID!
  name: String!
}

Bootstrap code:

builder.Services.AddGraphQLServer()
    .AddQueryType<Query>()
    .RegisterService<ParentRepository>()
    .AddApolloFederation();

Package versions:

<PackageReference Include="HotChocolate.ApolloFederation" Version="13.9.12" />
<PackageReference Include="HotChocolate.AspNetCore" Version="13.9.12" />

Solution

  • To output the schema with the @key directive, you can add the HotChocolate.AspNetCore.CommandLine package to the project per these instructions.

    Be sure to replace app.Run():

    //app.Run();
    
    await app.RunWithGraphQLCommandsAsync(args);
    

    Then you can execute the application passing in the schema export command line options.

    For example, when running from code:

    dotnet run -- schema export
    

    And voila, the output contains the @key directive!

    schema @link(url: "https:\/\/specs.apollo.dev\/federation\/v2.6", import: [ "@key", "@tag", "FieldSet" ]) {
      query: Query
    }
    
    type Parent @key(fields: "id") {
      id: ID!
      name: String!
    }
    
    type Query {
      allParents: [Parent!]!
      _service: _Service!
      _entities(representations: [_Any!]!): [_Entity]!
    }
    
    "This type provides a field named sdl: String! which exposes the SDL of the service's schema. This SDL (schema definition language) is a printed version of the service's schema including the annotations of federation directives. This SDL does not include the additions of the federation spec."
    type _Service {
      sdl: String!
    }
    
    "Union of all types that key directive applied. This information is needed by the Apollo federation gateway."
    union _Entity = Parent
    
    "Used to indicate a combination of fields that can be used to uniquely identify and fetch an object or interface."
    directive @key(fields: FieldSet! resolvable: Boolean = true) repeatable on OBJECT | INTERFACE
    
    "Links definitions within the document to external schemas."
    directive @link("Gets imported specification url." url: String! "Gets optional list of imported element names." import: [String!]) repeatable on SCHEMA
    
    "Scalar representing a set of fields."
    scalar FieldSet
    
    "The _Any scalar is used to pass representations of entities from external services into the root _entities field for execution. Validation of the _Any scalar is done by matching the __typename and @external fields defined in the schema."
    scalar _Any