apollographql / federation-hotchocolate

HotChocolate support for Apollo Federation
https://www.apollographql.com/docs/federation/
MIT License
16 stars 8 forks source link

Errors with `rover subgraph publish` due to invalid definition #59

Open damienpontifex opened 11 months ago

damienpontifex commented 11 months ago

Subgraph publish errors when using this library:

DIRECTIVE_DEFINITION_INVALID: [shop] Invalid definition for directive "@key": argument "fields" should have type "_FieldSet!" but found type "FieldSet!"
DIRECTIVE_DEFINITION_INVALID: [shop] Invalid definition for directive "@requires": argument "fields" should have type "_FieldSet!" but found type "FieldSet!"
DIRECTIVE_DEFINITION_INVALID: [shop] Invalid definition for directive "@provides": argument "fields" should have type "_FieldSet!" but found type "FieldSet!"

The directives that are written in the schema (whether through /graphql?sdl or rover subgraph introspect) are


directive @allowAnonymous repeatable on FIELD_DEFINITION

"Indicates to composition that the target element is accessible only to the authenticated supergraph users."
directive @authenticated on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM

directive @authorize("The name of the authorization policy that determines access to the annotated resource." policy: String "Roles that are allowed to access the annotated resource." roles: [String!] "Defines when when the authorize directive shall be applied.By default the authorize directives are applied during the validation phase." apply: ApplyPolicy! = BEFORE_RESOLVER) repeatable on OBJECT | FIELD_DEFINITION

"Marks underlying custom directive to be included in the Supergraph schema."
directive @composeDirective(name: String!) on SCHEMA

"Provides contact information of the owner responsible for this subgraph schema."
directive @contact(name: String! url: String description: String) on SCHEMA

"Directive to indicate that marks target object as extending part of the federated schema."
directive @extends on OBJECT | INTERFACE

"Directive to indicate that a field is owned by another service, for example via Apollo federation."
directive @external on OBJECT | FIELD_DEFINITION

"Marks location within schema as inaccessible from the GraphQL Gateway"
directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION

"Provides meta information to the router that this entity type is an interface in the supergraph."
directive @interfaceObject on OBJECT

"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

directive @link(url: String! import: [String]) repeatable on SCHEMA

"Overrides fields resolution logic from other subgraph. Used for migrating fields from one subgraph to another."
directive @override(from: String!) on FIELD_DEFINITION

"Used to annotate the expected returned fieldset from a field on a base type that is guaranteed to be selectable by the federation gateway."
directive @provides(fields: FieldSet!) on FIELD_DEFINITION

"Used to annotate the required input fieldset from a base type for a resolver."
directive @requires(fields: FieldSet!) on FIELD_DEFINITION

"Indicates to composition that the target element is accessible only to the authenticated supergraph users with the appropriate JWT scopes."
directive @requiresScopes(scopes: [[Scope!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM

"Indicates that given object and\/or field can be resolved by multiple subgraphs."
directive @shareable repeatable on OBJECT | FIELD_DEFINITION

"Allows users to annotate fields and types with additional metadata information."
directive @tag(name: String!) on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION

"The built-in `Decimal` scalar type."
scalar Decimal

"Scalar representing a set of fields."
scalar FieldSet

"Scalar representing a JWT scope"
scalar Scope

"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

Versions used

ApolloGraphQL.HotChocolate.Federation: 1.2.1 HotChocolate.* 13.6.1

Setup code

builder.Services.AddGraphQLServer()
    .AddApolloFederationV2(schemaConfiguration: schema =>
    {
        schema.Contact(
            name: "<value>",
            url: "<value>",
            description: "<value>"
        );
    })
    .AddDirectiveType<ContactDirectiveType>()
    .AddQueryType<Query>()
    .AddAuthorization()
    .AddInstrumentation(o =>
    {
        o.IncludeDocument = true;
        o.RenameRootActivity = true;
    })
    .InitializeOnStartup();
dariuszkuc commented 11 months ago

Hello 👋 This issue is generally caused when you are trying to upload Federation v2 schema (which uses FieldSet) as a Federation v1 schema (which used _FieldSet). Make sure your supergraph is using v2 composition and double check whether your generated SDL applies @link on your schema type.

damienpontifex commented 11 months ago

This is a new graph in studio and has 2.5 as the version

image

On my side/client side, this is using setup code as posted above, which (without specifying the version), I can see is using fed 2.5 https://github.com/apollographql/federation-hotchocolate/blob/e438fee84d74cb5e77f398caceb5a190e9827243/Federation/Extensions/ApolloFederationSchemaBuilderExtensionsV2.cs#L30-L33

The generated SDL definitely doesn't have @link, rather is declaring all the directives in the schema output (pasted above). Although I haven't configured anything to use or not use link, my assumption is it would do that automatically.

damienpontifex commented 11 months ago

Sample project reproducing the issue https://github.com/damienpontifex/HotChocolate.Fed.Issue

willgittoes commented 11 months ago

I had the same issue when I didn't have a link before my schema:

schema @link(url: "https:\/\/specs.apollo.dev\/federation\/v2.5", import: [ "@extends", "@external", "@key", "@inaccessible", "@override", "@provides", "@requires", "@shareable", "@tag", "FieldSet", "@composeDirective", "@interfaceObject" ]) {
  query: Query
}

For some reason this doesn't seem to be generated when I call BuildSchemaAsync().Print(), but when I add it in manually it will at least allow me to publish the subgraph schema.

Edit: Probably because of this: https://github.com/apollographql/federation-hotchocolate/issues/55

kirill-d-lappo commented 3 months ago

I created a basic project to test the issue

both rover config file and hotchocolate server are set to use 2.0 schema

I tested it using rover 0.24.0 and now I am getting an error like

error[E029]: Encountered 1 build error while trying to build a supergraph.

Caused by:
    UNKNOWN: [service-1] Invalid definition for directive "@shareable": "@shareable" should not be repeatable

see schema.graphql to check schema, it is generated at build time

HotChocolateFederationIssue.zip