Skip to content

Commit

Permalink
feat: add support for federation 2.9 (#417)
Browse files Browse the repository at this point in the history
  • Loading branch information
tninesling authored Sep 5, 2024
1 parent 28e1065 commit b9af10d
Show file tree
Hide file tree
Showing 10 changed files with 415 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public final class Federation {
public static final String FEDERATION_SPEC_V2_6 = "https://specs.apollo.dev/federation/v2.6";
public static final String FEDERATION_SPEC_V2_7 = "https://specs.apollo.dev/federation/v2.7";
public static final String FEDERATION_SPEC_V2_8 = "https://specs.apollo.dev/federation/v2.8";
public static final String FEDERATION_SPEC_V2_9 = "https://specs.apollo.dev/federation/v2.9";

private static final SchemaGenerator.Options defaultGeneratorOptions =
SchemaGenerator.Options.defaultOptions();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static com.apollographql.federation.graphqljava.Federation.FEDERATION_SPEC_V2_6;
import static com.apollographql.federation.graphqljava.Federation.FEDERATION_SPEC_V2_7;
import static com.apollographql.federation.graphqljava.Federation.FEDERATION_SPEC_V2_8;
import static com.apollographql.federation.graphqljava.Federation.FEDERATION_SPEC_V2_9;
import static graphql.introspection.Introspection.DirectiveLocation.FIELD_DEFINITION;
import static graphql.introspection.Introspection.DirectiveLocation.INTERFACE;
import static graphql.introspection.Introspection.DirectiveLocation.OBJECT;
Expand Down Expand Up @@ -232,6 +233,8 @@ public static List<SDLNamedDefinition> loadFederationSpecDefinitions(String fede
return loadFed2Definitions("definitions_fed2_7.graphqls");
case FEDERATION_SPEC_V2_8:
return loadFed2Definitions("definitions_fed2_8.graphqls");
case FEDERATION_SPEC_V2_9:
return loadFed2Definitions("definitions_fed2_9.graphqls");
default:
throw new UnsupportedFederationVersionException(federationSpec);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ public final class LinkDirectiveProcessor {
"@interfaceObject", 23,
"@authenticated", 25,
"@requiresScopes", 25,
"@policy", 26);
"@policy", 26,
"@context", 28,
"@fromContext", 28,
"@cost", 29,
"@listSize", 29);

private LinkDirectiveProcessor() {}

Expand Down
136 changes: 136 additions & 0 deletions graphql-java-support/src/main/resources/definitions_fed2_9.graphqls
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#
# https://specs.apollo.dev/federation/v2.0/federation-v2.0.graphql
#

directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE
directive @requires(fields: FieldSet!) on FIELD_DEFINITION
directive @provides(fields: FieldSet!) on FIELD_DEFINITION
directive @external on OBJECT | FIELD_DEFINITION
directive @extends on OBJECT | INTERFACE
directive @inaccessible on
| FIELD_DEFINITION
| OBJECT
| INTERFACE
| UNION
| ENUM
| ENUM_VALUE
| SCALAR
| INPUT_OBJECT
| INPUT_FIELD_DEFINITION
| ARGUMENT_DEFINITION
directive @tag(name: String!) repeatable on
| FIELD_DEFINITION
| INTERFACE
| OBJECT
| UNION
| ARGUMENT_DEFINITION
| SCALAR
| ENUM
| ENUM_VALUE
| INPUT_OBJECT
| INPUT_FIELD_DEFINITION
scalar FieldSet

#
# https://specs.apollo.dev/link/v1.0/link-v1.0.graphql
#

directive @link(
url: String!,
as: String,
import: [Import],
for: Purpose)
repeatable on SCHEMA

scalar Import

enum Purpose {
SECURITY
EXECUTION
}

#
# federation-v2.1
#

directive @composeDirective(name: String!) repeatable on SCHEMA

#
# federation-v2.2
#

directive @shareable repeatable on FIELD_DEFINITION | OBJECT

#
# federation-v2.3
#

directive @interfaceObject on OBJECT

#
# federation-v2.5
#

directive @authenticated on
ENUM
| FIELD_DEFINITION
| INTERFACE
| OBJECT
| SCALAR

directive @requiresScopes(scopes: [[Scope!]!]!) on
ENUM
| FIELD_DEFINITION
| INTERFACE
| OBJECT
| SCALAR

scalar Scope

#
# federation-v2.6
#

directive @policy(policies: [[Policy!]!]!) on
ENUM
| FIELD_DEFINITION
| INTERFACE
| OBJECT
| SCALAR

scalar Policy

#
# federation-v2.7
#

directive @override(from: String!, label: String) on FIELD_DEFINITION

#
# federation-v2.8
#

scalar ContextFieldValue

directive @context(name: String!) repeatable on INTERFACE | OBJECT | UNION

directive @fromContext(field: ContextFieldValue) on ARGUMENT_DEFINITION

#
# federation-v2.9
#

directive @cost(weight: Int!) on
ARGUMENT_DEFINITION
| ENUM
| FIELD_DEFINITION
| INPUT_FIELD_DEFINITION
| OBJECT
| SCALAR

directive @listSize(
assumedSize: Int,
slicingArguments: [String!],
sizedFields: [String!],
requireOneSlicingArgument: Boolean = true
) on FIELD_DEFINITION
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,14 @@ public void verifyFederationV2Transformation_context() {
verifyFederationTransformation("schemas/context/schema.graphql");
}

@Test
public void verifyFederationV2Transformation_contextFromUnsupportedVersion_throwsException() {
final String schemaSDL = FileUtils.readResource("schemas/invalidSpecVersionContext.graphql");
assertThrows(
UnsupportedLinkImportException.class,
() -> Federation.transform(schemaSDL).fetchEntities(env -> null).build());
}

@Test
public void
verifyFederationV2Transformation_requiresScopesFromUnsupportedVersion_throwsException() {
Expand Down Expand Up @@ -370,6 +378,19 @@ public void verifyFederationV2Transformation_scalarsDefinedInSchemaButNotWired()
verifyFederationTransformation("schemas/scalars/schema.graphql");
}

@Test
public void verifyFederationV2Transformation_cost() {
verifyFederationTransformation("schemas/cost/schema.graphql");
}

@Test
public void verifyFederationV2Transformation_costFromUnsupportedVersion_throwsException() {
final String schemaSDL = FileUtils.readResource("schemas/invalidSpecVersionCost.graphql");
assertThrows(
UnsupportedLinkImportException.class,
() -> Federation.transform(schemaSDL).fetchEntities(env -> null).build());
}

private void verifyFederationTransformation(String schemaFileName) {
final RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring().build();
verifyFederationTransformation(schemaFileName, runtimeWiring);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
extend schema
@link(
url: "https://specs.apollo.dev/federation/v2.9"
import: ["@cost", "@key", "@listSize"]
)

type Product @key(fields: "id") {
id: ID!
name: String!
child: Child! @cost(weight: 5)
}

type Child @key(fields: "id") {
id: ID!
details(productName: String): [String!] @listSize(assumedSize: 10)
}

type Query {
product(id: ID!): Product
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
schema @link(import : ["@cost", "@key", "@listSize"], url : "https://specs.apollo.dev/federation/v2.9"){
query: Query
}

directive @cost(weight: Int!) on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM | INPUT_FIELD_DEFINITION

directive @federation__authenticated on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM

directive @federation__composeDirective(name: String!) repeatable on SCHEMA

directive @federation__context(name: String!) repeatable on OBJECT | INTERFACE | UNION

directive @federation__extends on OBJECT | INTERFACE

directive @federation__external on OBJECT | FIELD_DEFINITION

directive @federation__fromContext(field: federation__ContextFieldValue) on ARGUMENT_DEFINITION

directive @federation__interfaceObject on OBJECT

directive @federation__override(from: String!, label: String) on FIELD_DEFINITION

directive @federation__policy(policies: [[federation__Policy!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM

directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION

directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION

directive @federation__requiresScopes(scopes: [[federation__Scope!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM

directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION

directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION

directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE

directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA

directive @listSize(assumedSize: Int, requireOneSlicingArgument: Boolean = true, sizedFields: [String!], slicingArguments: [String!]) on FIELD_DEFINITION

directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION

union _Entity = Child | Product

type Child @key(fields : "id", resolvable : true) {
details(productName: String): [String!] @listSize(assumedSize : 10, requireOneSlicingArgument : true)
id: ID!
}

type Product @key(fields : "id", resolvable : true) {
child: Child! @cost(weight : 5)
id: ID!
name: String!
}

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

type _Service {
sdl: String!
}

enum link__Purpose {
EXECUTION
SECURITY
}

scalar _Any

scalar federation__ContextFieldValue

scalar federation__FieldSet

scalar federation__Policy

scalar federation__Scope

scalar link__Import
Loading

0 comments on commit b9af10d

Please sign in to comment.