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

Fixed ApolloFederation FieldSet directives. #6838

Merged
merged 5 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,7 @@ public override IEnumerable<TypeReference> RegisterMoreTypes(
yield return _typeInspector.GetTypeRef(typeof(LinkDirective));
}
}



public override void OnBeforeCompleteName(
ITypeCompletionContext completionContext,
DefinitionBase definition)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ public static IObjectTypeDescriptor<T> ExtendServiceType<T>(
{
ArgumentNullException.ThrowIfNull(descriptor);

descriptor.Directive(ExtendServiceTypeDirective.Default);
if (descriptor.Extend().Context.GetFederationVersion() == FederationVersion.Federation10)
{
descriptor.Directive(ExtendServiceTypeDirective.Default);
}

return descriptor;
}

Expand Down Expand Up @@ -62,7 +66,11 @@ public static IObjectTypeDescriptor ExtendServiceType(
{
ArgumentNullException.ThrowIfNull(descriptor);

descriptor.Directive(ExtendServiceTypeDirective.Default);
if (descriptor.Extend().Context.GetFederationVersion() == FederationVersion.Federation10)
{
descriptor.Directive(ExtendServiceTypeDirective.Default);
}

return descriptor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,22 @@ namespace HotChocolate.ApolloFederation.Types;
[KeyLegacySupport]
public sealed class KeyDirective
{
public KeyDirective(string fieldSet, bool resolvable = true)
public KeyDirective(string fields, bool resolvable = true)
{
ArgumentException.ThrowIfNullOrEmpty(fieldSet);
FieldSet = FieldSetType.ParseSelectionSet(fieldSet);
ArgumentException.ThrowIfNullOrEmpty(fields);
Fields = FieldSetType.ParseSelectionSet(fields);
Resolvable = resolvable;
}

public KeyDirective(SelectionSetNode fieldSet, bool resolvable = true)
public KeyDirective(SelectionSetNode fields, bool resolvable = true)
{
ArgumentNullException.ThrowIfNull(fieldSet);
FieldSet = fieldSet;
ArgumentNullException.ThrowIfNull(fields);
Fields = fields;
Resolvable = resolvable;
}

[FieldSet]
public SelectionSetNode FieldSet { get; }
public SelectionSetNode Fields { get; }

[GraphQLType<BooleanType>]
[DefaultValue(true)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ protected override void OnConfigure(
{
var desc = (IDirectiveTypeDescriptor<KeyDirective>)descriptor;
desc.BindArgumentsExplicitly();
desc.Argument(t => t.FieldSet);
desc.Argument(t => t.Fields);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using HotChocolate.Language;
using static HotChocolate.ApolloFederation.FederationTypeNames;
using static HotChocolate.ApolloFederation.FederationVersionUrls;
using static HotChocolate.ApolloFederation.Properties.FederationResources;
using DirectiveLocation = HotChocolate.Types.DirectiveLocation;

namespace HotChocolate.ApolloFederation.Types;

Expand Down Expand Up @@ -34,8 +36,20 @@ namespace HotChocolate.ApolloFederation.Types;
[Package(Federation20)]
[DirectiveType(ProvidesDirective_Name, DirectiveLocation.FieldDefinition)]
[GraphQLDescription(ProvidesDirective_Description)]
public sealed class ProvidesDirective(string fieldSet)
public sealed class ProvidesDirective
{
public ProvidesDirective(string fields)
{
ArgumentException.ThrowIfNullOrEmpty(fields);
Fields = FieldSetType.ParseSelectionSet(fields);
}

public ProvidesDirective(SelectionSetNode fields)
{
ArgumentNullException.ThrowIfNull(fields);
Fields = fields;
}

[FieldSet]
public string FieldSet { get; } = fieldSet;
public SelectionSetNode Fields { get; }
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using HotChocolate.Language;
using static HotChocolate.ApolloFederation.FederationTypeNames;
using static HotChocolate.ApolloFederation.FederationVersionUrls;
using static HotChocolate.ApolloFederation.Properties.FederationResources;
using DirectiveLocation = HotChocolate.Types.DirectiveLocation;

namespace HotChocolate.ApolloFederation.Types;

Expand All @@ -27,8 +29,20 @@ namespace HotChocolate.ApolloFederation.Types;
[Package(Federation20)]
[DirectiveType(RequiresDirective_Name, DirectiveLocation.FieldDefinition)]
[GraphQLDescription(RequiresDirective_Description)]
public sealed class RequiresDirective(string fieldSet)
public sealed class RequiresDirective
{
public RequiresDirective(string fields)
{
ArgumentException.ThrowIfNullOrEmpty(fields);
Fields = FieldSetType.ParseSelectionSet(fields);
}

public RequiresDirective(SelectionSetNode fields)
{
ArgumentNullException.ThrowIfNull(fields);
Fields = fields;
}

[FieldSet]
public string FieldSet { get; } = fieldSet;
public SelectionSetNode Fields { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public static class ServerFields
internal static ObjectFieldDefinition CreateServiceField(IDescriptorContext context)
{
var descriptor = ObjectFieldDescriptor.New(context, WellKnownFieldNames.Service);
descriptor.Resolve(_service);
descriptor.Type<NonNullType<ObjectType<_Service>>>().Resolve(_service);
descriptor.Definition.PureResolver = Resolve;

static _Service Resolve(IPureResolverContext ctx)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"data": {
"product": {
"createdBy": {
"email": "support@apollographql.com",
"email": "contact@chillicream.com",
"totalProductsCreated": 1337
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
schema @link(url: "https:\/\/specs.apollo.dev\/federation\/v2.5", import: [ "@extends", "@external", "@key", "@inaccessible", "@override", "@provides", "@requires", "@shareable", "@tag", "FieldSet", "@composeDirective", "@interfaceObject", "@authenticated", "@requiresPolicy" ]) {
schema @link(url: "https:\/\/specs.apollo.dev\/federation\/v2.0", import: [ "@key", "@provides", "FieldSet", "@external" ]) {
query: Query
}

Expand Down Expand Up @@ -39,37 +39,20 @@ type _Service {
"Union of all types that key directive applied. This information is needed by the Apollo federation gateway."
union _Entity = Product | User

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

"Marks underlying custom directive to be included in the Supergraph schema."
directive @composeDirective(name: 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 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 @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
"Object representation of @link directive."
directive @link("Gets imported specification url." url: String! "Gets optional list of imported element names." import: [String!]) repeatable on SCHEMA

"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
directive @provides(fields: FieldSet!) on FIELD_DEFINITION

"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

"Scalar representing a set of fields."
scalar _FieldSet
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
schema @link(url: "https:\/\/specs.apollo.dev\/federation\/v2.5", import: [ "@extends", "@external", "@key", "@inaccessible", "@override", "@provides", "@requires", "@shareable", "@tag", "FieldSet", "@composeDirective", "@interfaceObject", "@authenticated", "@requiresPolicy" ]) {
schema @link(url: "https:\/\/specs.apollo.dev\/federation\/v2.0", import: [ "@key", "@provides", "FieldSet", "@external" ]) {
query: Query
}

Expand Down Expand Up @@ -30,3 +30,29 @@ type User @key(fields: "email") {
email: ID! @external
totalProductsCreated: Int @external
}

"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 = Product | User

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

"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

"Object representation of @link directive."
directive @link("Gets imported specification url." url: String! "Gets optional list of imported element names." import: [String!]) repeatable on SCHEMA

"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

"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
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
schema @link(url: "https:\/\/specs.apollo.dev\/federation\/v2.5", import: [ "@extends", "@external", "@key", "@inaccessible", "@override", "@provides", "@requires", "@shareable", "@tag", "FieldSet", "@composeDirective", "@interfaceObject", "@authenticated", "@requiresPolicy" ]) {
schema @link(url: "https:\/\/specs.apollo.dev\/federation\/v2.0", import: [ "@key", "@provides", "@external", "FieldSet" ]) {
query: Query
}

Expand Down Expand Up @@ -39,37 +39,20 @@ type _Service {
"Union of all types that key directive applied. This information is needed by the Apollo federation gateway."
union _Entity = Product | User

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

"Marks underlying custom directive to be included in the Supergraph schema."
directive @composeDirective(name: 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 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 @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
"Object representation of @link directive."
directive @link("Gets imported specification url." url: String! "Gets optional list of imported element names." import: [String!]) repeatable on SCHEMA

"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
directive @provides(fields: FieldSet!) on FIELD_DEFINITION

"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

"Scalar representing a set of fields."
scalar _FieldSet
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
schema @link(url: "https:\/\/specs.apollo.dev\/federation\/v2.5", import: [ "@extends", "@external", "@key", "@inaccessible", "@override", "@provides", "@requires", "@shareable", "@tag", "FieldSet", "@composeDirective", "@interfaceObject", "@authenticated", "@requiresPolicy" ]) {
schema @link(url: "https:\/\/specs.apollo.dev\/federation\/v2.0", import: [ "@key", "@provides", "@external", "FieldSet" ]) {
query: Query
}

Expand Down Expand Up @@ -30,3 +30,29 @@ type User @key(fields: "email") {
email: ID! @external
totalProductsCreated: Int @external
}

"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 = Product | User

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

"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

"Object representation of @link directive."
directive @link("Gets imported specification url." url: String! "Gets optional list of imported element names." import: [String!]) repeatable on SCHEMA

"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

"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
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ schema @link(url: "https:\/\/specs.apollo.dev\/federation\/v2.0", import: [ "@ke
query: Query
}

type Address @key(fieldSet: "matchCode") {
type Address @key(fields: "matchCode") {
matchCode: String
}

type Query {
_service: _Service
_service: _Service!
_entities(representations: [_Any!]!): [_Entity]!
}

Expand All @@ -57,7 +57,7 @@ type _Service {
union _Entity = Address

"Used to indicate a combination of fields that can be used to uniquely identify and fetch an object or interface."
directive @key(fieldSet: FieldSet! resolvable: Boolean = true) repeatable on OBJECT | INTERFACE
directive @key(fields: FieldSet! resolvable: Boolean = true) repeatable on OBJECT | INTERFACE

"Object representation of @link directive."
directive @link("Gets imported specification url." url: String! "Gets optional list of imported element names." import: [String!]) repeatable on SCHEMA
Expand All @@ -76,7 +76,7 @@ public async Task TestServiceTypeTypePureCodeFirst()
// arrange
var schema = await new ServiceCollection()
.AddGraphQL()
.AddApolloFederation()
.AddApolloFederation(FederationVersion.Federation22)
.AddQueryType<Query>()
.BuildSchemaAsync();

Expand All @@ -95,13 +95,13 @@ schema @link(url: "https:\/\/specs.apollo.dev\/federation\/v2.0", import: [ "@ke
query: Query
}

type Address @key(fieldSet: "matchCode") {
type Address @key(fields: "matchCode") {
matchCode: String
}

type Query {
address(id: Int!): Address!
_service: _Service
_service: _Service!
_entities(representations: [_Any!]!): [_Entity]!
}

Expand All @@ -114,7 +114,7 @@ type _Service {
union _Entity = Address

"Used to indicate a combination of fields that can be used to uniquely identify and fetch an object or interface."
directive @key(fieldSet: FieldSet! resolvable: Boolean = true) repeatable on OBJECT | INTERFACE
directive @key(fields: FieldSet! resolvable: Boolean = true) repeatable on OBJECT | INTERFACE

"Object representation of @link directive."
directive @link("Gets imported specification url." url: String! "Gets optional list of imported element names." import: [String!]) repeatable on SCHEMA
Expand Down
Loading