Skip to content

Commit 0ad2582

Browse files
authored
feat: federation 2.5 support (#347)
Adds support for [Federation specification v2.5](https://www.apollographql.com/docs/federation/federation-versions#v25). Changes: * new `@authenticated` directive ```graphql directive @authenticated on ENUM | FIELD_DEFINITION | INTERFACE | OBJECT | SCALAR ``` * new `@requiresScopes` directive ```graphql directive @requiresScopes(scopes: [[Scope!]!]!) on ENUM | FIELD_DEFINITION | INTERFACE | OBJECT | SCALAR scalar Scope ```
1 parent e78025f commit 0ad2582

File tree

11 files changed

+256
-7
lines changed

11 files changed

+256
-7
lines changed

.github/workflows/compatibility.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
run: ./gradlew bootJar
3535

3636
- name: Compatibility Test
37-
uses: apollographql/federation-subgraph-compatibility@v1
37+
uses: apollographql/federation-subgraph-compatibility@v2
3838
with:
3939
compose: 'docker-compose.yaml'
4040
schema: 'src/main/resources/graphql/schema.graphqls'

compatibility/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM gradle:8.2.1-jdk17
1+
FROM openjdk:17
22

33
EXPOSE 4001
44
RUN mkdir /app

compatibility/src/main/resources/graphql/schema.graphqls

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
extend schema
22
@link(
3-
url: "https://specs.apollo.dev/federation/v2.3",
3+
url: "https://specs.apollo.dev/federation/v2.5",
44
import: [
55
"@composeDirective",
66
"@extends",

graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/Federation.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ public final class Federation {
2727

2828
public static final String FEDERATION_SPEC_V2_0 = "https://specs.apollo.dev/federation/v2.0";
2929
public static final String FEDERATION_SPEC_V2_1 = "https://specs.apollo.dev/federation/v2.1";
30-
3130
public static final String FEDERATION_SPEC_V2_2 = "https://specs.apollo.dev/federation/v2.2";
32-
3331
public static final String FEDERATION_SPEC_V2_3 = "https://specs.apollo.dev/federation/v2.3";
32+
public static final String FEDERATION_SPEC_V2_4 = "https://specs.apollo.dev/federation/v2.4";
33+
public static final String FEDERATION_SPEC_V2_5 = "https://specs.apollo.dev/federation/v2.5";
3434

3535
private static final SchemaGenerator.Options generatorOptions =
3636
SchemaGenerator.Options.defaultOptions();

graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationDirectives.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import static com.apollographql.federation.graphqljava.Federation.FEDERATION_SPEC_V2_1;
55
import static com.apollographql.federation.graphqljava.Federation.FEDERATION_SPEC_V2_2;
66
import static com.apollographql.federation.graphqljava.Federation.FEDERATION_SPEC_V2_3;
7+
import static com.apollographql.federation.graphqljava.Federation.FEDERATION_SPEC_V2_4;
8+
import static com.apollographql.federation.graphqljava.Federation.FEDERATION_SPEC_V2_5;
79
import static graphql.introspection.Introspection.DirectiveLocation.FIELD_DEFINITION;
810
import static graphql.introspection.Introspection.DirectiveLocation.INTERFACE;
911
import static graphql.introspection.Introspection.DirectiveLocation.OBJECT;
@@ -15,7 +17,13 @@
1517

1618
import com.apollographql.federation.graphqljava.exceptions.UnsupportedFederationVersionException;
1719
import graphql.PublicApi;
18-
import graphql.language.*;
20+
import graphql.language.DirectiveDefinition;
21+
import graphql.language.DirectiveLocation;
22+
import graphql.language.Document;
23+
import graphql.language.InputValueDefinition;
24+
import graphql.language.NonNullType;
25+
import graphql.language.SDLNamedDefinition;
26+
import graphql.language.TypeName;
1927
import graphql.parser.Parser;
2028
import graphql.schema.GraphQLArgument;
2129
import graphql.schema.GraphQLDirective;
@@ -25,7 +33,12 @@
2533
import java.io.InputStream;
2634
import java.io.InputStreamReader;
2735
import java.nio.charset.StandardCharsets;
28-
import java.util.*;
36+
import java.util.Arrays;
37+
import java.util.Collections;
38+
import java.util.Comparator;
39+
import java.util.LinkedHashSet;
40+
import java.util.List;
41+
import java.util.Set;
2942
import java.util.stream.Collectors;
3043
import java.util.stream.Stream;
3144

@@ -206,7 +219,10 @@ public static List<SDLNamedDefinition> loadFederationSpecDefinitions(String fede
206219
case FEDERATION_SPEC_V2_2:
207220
return loadFed2Definitions("definitions_fed2_2.graphqls");
208221
case FEDERATION_SPEC_V2_3:
222+
case FEDERATION_SPEC_V2_4:
209223
return loadFed2Definitions("definitions_fed2_3.graphqls");
224+
case FEDERATION_SPEC_V2_5:
225+
return loadFed2Definitions("definitions_fed2_5.graphqls");
210226
default:
211227
throw new UnsupportedFederationVersionException(federationSpec);
212228
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#
2+
# https://specs.apollo.dev/federation/v2.0/federation-v2.0.graphql
3+
#
4+
5+
directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE
6+
directive @requires(fields: FieldSet!) on FIELD_DEFINITION
7+
directive @provides(fields: FieldSet!) on FIELD_DEFINITION
8+
directive @external on OBJECT | FIELD_DEFINITION
9+
directive @extends on OBJECT | INTERFACE
10+
directive @override(from: String!) on FIELD_DEFINITION
11+
directive @inaccessible on
12+
| FIELD_DEFINITION
13+
| OBJECT
14+
| INTERFACE
15+
| UNION
16+
| ENUM
17+
| ENUM_VALUE
18+
| SCALAR
19+
| INPUT_OBJECT
20+
| INPUT_FIELD_DEFINITION
21+
| ARGUMENT_DEFINITION
22+
directive @tag(name: String!) repeatable on
23+
| FIELD_DEFINITION
24+
| INTERFACE
25+
| OBJECT
26+
| UNION
27+
| ARGUMENT_DEFINITION
28+
| SCALAR
29+
| ENUM
30+
| ENUM_VALUE
31+
| INPUT_OBJECT
32+
| INPUT_FIELD_DEFINITION
33+
scalar FieldSet
34+
35+
#
36+
# https://specs.apollo.dev/link/v1.0/link-v1.0.graphql
37+
#
38+
39+
directive @link(
40+
url: String!,
41+
as: String,
42+
import: [Import])
43+
repeatable on SCHEMA
44+
45+
scalar Import
46+
47+
#
48+
# federation-v2.1
49+
#
50+
51+
directive @composeDirective(name: String!) repeatable on SCHEMA
52+
53+
#
54+
# federation-v2.2
55+
#
56+
57+
directive @shareable repeatable on FIELD_DEFINITION | OBJECT
58+
59+
#
60+
# federation-v2.3
61+
#
62+
63+
directive @interfaceObject on OBJECT
64+
65+
#
66+
# federation-v2.5
67+
#
68+
69+
directive @authenticated on
70+
ENUM
71+
| FIELD_DEFINITION
72+
| INTERFACE
73+
| OBJECT
74+
| SCALAR
75+
76+
directive @requiresScopes(scopes: [[Scope!]!]!) on
77+
ENUM
78+
| FIELD_DEFINITION
79+
| INTERFACE
80+
| OBJECT
81+
| SCALAR
82+
83+
scalar Scope

graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/FederationTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,16 @@ public void verifyFederationV2Transformation_nonResolvableKey_doesNotRequireReso
299299
FederatedSchemaVerifier.verifyServiceSDL(federatedSchema, expectedFederatedSchemaSDL);
300300
}
301301

302+
@Test
303+
public void verifyFederationV2Transformation_authorization() {
304+
verifyFederationTransformation("schemas/authorization.graphql", true);
305+
}
306+
307+
@Test
308+
public void verifyFederationV2Transformation_customAuthenticated() {
309+
verifyFederationTransformation("schemas/customAuthenticated.graphql", true);
310+
}
311+
302312
private GraphQLSchema verifyFederationTransformation(
303313
String schemaFileName, boolean isFederationV2) {
304314
final RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring().build();
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
extend schema @link(url: "https://specs.apollo.dev/federation/v2.5", import: ["@authenticated", "@key", "@requiresScopes", "Scope", "FieldSet"])
2+
3+
type Product @key(fields: "id") {
4+
id: ID!
5+
name: String!
6+
supplier: String @requiresScopes(scopes: [["scopeA"]])
7+
}
8+
9+
type Query {
10+
product(id: ID!): Product @authenticated
11+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
schema @link(import : ["@authenticated", "@key", "@requiresScopes", "Scope", "FieldSet"], url : "https://specs.apollo.dev/federation/v2.5"){
2+
query: Query
3+
}
4+
5+
directive @authenticated on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM
6+
7+
directive @federation__composeDirective(name: String!) repeatable on SCHEMA
8+
9+
directive @federation__extends on OBJECT | INTERFACE
10+
11+
directive @federation__external on OBJECT | FIELD_DEFINITION
12+
13+
directive @federation__interfaceObject on OBJECT
14+
15+
directive @federation__override(from: String!) on FIELD_DEFINITION
16+
17+
directive @federation__provides(fields: FieldSet!) on FIELD_DEFINITION
18+
19+
directive @federation__requires(fields: FieldSet!) on FIELD_DEFINITION
20+
21+
directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION
22+
23+
directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
24+
25+
directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE
26+
27+
directive @link(as: String, import: [link__Import], url: String!) repeatable on SCHEMA
28+
29+
directive @requiresScopes(scopes: [[Scope!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM
30+
31+
directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
32+
33+
union _Entity = Product
34+
35+
type Product @key(fields : "id", resolvable : true) {
36+
id: ID!
37+
name: String!
38+
supplier: String @requiresScopes(scopes : [["scopeA"]])
39+
}
40+
41+
type Query {
42+
_entities(representations: [_Any!]!): [_Entity]!
43+
_service: _Service!
44+
product(id: ID!): Product @authenticated
45+
}
46+
47+
type _Service {
48+
sdl: String!
49+
}
50+
51+
scalar FieldSet
52+
53+
scalar Scope
54+
55+
scalar _Any
56+
57+
scalar link__Import
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
extend schema @link(url: "https://specs.apollo.dev/federation/v2.5", import: ["@key"])
2+
3+
directive @authenticated(role: [String!]!) on FIELD_DEFINITION
4+
5+
type Product @key(fields: "id") {
6+
id: ID!
7+
name: String!
8+
supplier: String @authenticated(role: ["manager"])
9+
}
10+
11+
type Query {
12+
product(id: ID!): Product
13+
}

0 commit comments

Comments
 (0)