diff --git a/server/implementation/src/main/java/io/smallrye/graphql/SmallRyeGraphQLServerLogging.java b/server/implementation/src/main/java/io/smallrye/graphql/SmallRyeGraphQLServerLogging.java index 22b0cc677..2315e44db 100644 --- a/server/implementation/src/main/java/io/smallrye/graphql/SmallRyeGraphQLServerLogging.java +++ b/server/implementation/src/main/java/io/smallrye/graphql/SmallRyeGraphQLServerLogging.java @@ -94,4 +94,7 @@ public interface SmallRyeGraphQLServerLogging { @Message(id = 15000, value = "Using %s service for context propagation") void usingContextPropagationService(String name); + @LogMessage(level = Logger.Level.DEBUG) + @Message(id = 16000, value = "Enable GraphQL Federation") + void enableFederation(); } diff --git a/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java b/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java index 714f897fd..bcaea3a7f 100644 --- a/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java +++ b/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java @@ -180,6 +180,7 @@ private void generateGraphQLSchema() { JsonInputRegistry.override(overrides); if (Config.get().isFederationEnabled()) { + log.enableFederation(); GraphQLSchema rawSchema = schemaBuilder.build(); this.graphQLSchema = Federation.transform(rawSchema) .fetchEntities(new FederationDataFetcher(rawSchema.getQueryType(), rawSchema.getCodeRegistry())) diff --git a/server/runner/src/main/resources/META-INF/microprofile-config.properties b/server/runner/src/main/resources/META-INF/microprofile-config.properties index e8ffdb645..a0f830535 100644 --- a/server/runner/src/main/resources/META-INF/microprofile-config.properties +++ b/server/runner/src/main/resources/META-INF/microprofile-config.properties @@ -2,7 +2,7 @@ smallrye.graphql.printDataFetcherException=true smallrye.graphql.tracing.enabled=true smallrye.graphql.allowGet=true smallrye.graphql.logPayload=true - mp.graphql.showErrorMessage=java.security.AccessControlException,io.smallrye.graphql.test.apps.exceptionlist.* mp.graphql.hideErrorMessage=java.io.IOException,io.smallrye.graphql.test.apps.exceptionlist.* -smallrye.graphql.errorExtensionFields=exception,classification,code,description,validationErrorType,queryPath \ No newline at end of file +smallrye.graphql.errorExtensionFields=exception,classification,code,description,validationErrorType,queryPath +smallrye.graphql.federation.enabled=true diff --git a/server/tck/src/test/java/io/smallrye/graphql/test/apps/federation/price/api/Prices.java b/server/tck/src/test/java/io/smallrye/graphql/test/apps/federation/price/api/Prices.java new file mode 100644 index 000000000..11bf7d028 --- /dev/null +++ b/server/tck/src/test/java/io/smallrye/graphql/test/apps/federation/price/api/Prices.java @@ -0,0 +1,23 @@ +package io.smallrye.graphql.test.apps.federation.price.api; + +import static java.util.Arrays.asList; + +import java.util.List; + +import org.eclipse.microprofile.graphql.GraphQLApi; +import org.eclipse.microprofile.graphql.Id; +import org.eclipse.microprofile.graphql.Query; + +@GraphQLApi +public class Prices { + private static final List PRICES = asList( + ProductWithPrice.product("1", 100), + ProductWithPrice.product("2", 400)); + + @Query + public ProductWithPrice product(@Id String id) { + return PRICES.stream() + .filter(productWithPrice -> productWithPrice.getId().equals(id)) + .findFirst().orElseThrow(() -> new RuntimeException("product not find")); + } +} diff --git a/server/tck/src/test/java/io/smallrye/graphql/test/apps/federation/price/api/ProductWithPrice.java b/server/tck/src/test/java/io/smallrye/graphql/test/apps/federation/price/api/ProductWithPrice.java new file mode 100644 index 000000000..19131afb6 --- /dev/null +++ b/server/tck/src/test/java/io/smallrye/graphql/test/apps/federation/price/api/ProductWithPrice.java @@ -0,0 +1,40 @@ +package io.smallrye.graphql.test.apps.federation.price.api; + +import org.eclipse.microprofile.graphql.Id; + +import io.smallrye.graphql.api.federation.Extends; +import io.smallrye.graphql.api.federation.Key; + +/** + * In a real federated service, this would also be a {@code Price}, but we can't have the same type twice within one service. + */ +@Key(fields = "id") +@Extends +public class ProductWithPrice { + public static ProductWithPrice product(String id, int price) { + ProductWithPrice product = new ProductWithPrice(); + product.setId(id); + product.setPrice(price); + return product; + } + + @Id + private String id; + private int price; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public int getPrice() { + return price; + } + + public void setPrice(int price) { + this.price = price; + } +} diff --git a/server/tck/src/test/java/io/smallrye/graphql/test/apps/federation/product/api/Product.java b/server/tck/src/test/java/io/smallrye/graphql/test/apps/federation/product/api/Product.java new file mode 100644 index 000000000..aa6ee7de6 --- /dev/null +++ b/server/tck/src/test/java/io/smallrye/graphql/test/apps/federation/product/api/Product.java @@ -0,0 +1,35 @@ +package io.smallrye.graphql.test.apps.federation.product.api; + +import org.eclipse.microprofile.graphql.Id; + +import io.smallrye.graphql.api.federation.Key; + +@Key(fields = "id") +public class Product { + static Product product(String id, String name) { + Product product = new Product(); + product.setId(id); + product.setName(name); + return product; + } + + @Id + private String id; + private String name; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/server/tck/src/test/java/io/smallrye/graphql/test/apps/federation/product/api/Products.java b/server/tck/src/test/java/io/smallrye/graphql/test/apps/federation/product/api/Products.java new file mode 100644 index 000000000..5b91aedb6 --- /dev/null +++ b/server/tck/src/test/java/io/smallrye/graphql/test/apps/federation/product/api/Products.java @@ -0,0 +1,23 @@ +package io.smallrye.graphql.test.apps.federation.product.api; + +import static java.util.Arrays.asList; + +import java.util.List; + +import org.eclipse.microprofile.graphql.GraphQLApi; +import org.eclipse.microprofile.graphql.Id; +import org.eclipse.microprofile.graphql.Query; + +@GraphQLApi +public class Products { + private static final List PRODUCTS = asList( + Product.product("1", "Armchair"), + Product.product("2", "Table")); + + @Query + public Product product(@Id String id) { + return PRODUCTS.stream() + .filter(product -> product.getId().equals(id)) + .findFirst().orElseThrow(() -> new RuntimeException("product not find")); + } +} diff --git a/server/tck/src/test/resources/tests/federation/input.graphql b/server/tck/src/test/resources/tests/federation/input.graphql new file mode 100644 index 000000000..a1b066fae --- /dev/null +++ b/server/tck/src/test/resources/tests/federation/input.graphql @@ -0,0 +1,8 @@ +{ + deepList{ + names + } + deepListFoo{ + bar + } +} \ No newline at end of file diff --git a/server/tck/src/test/resources/tests/federation/output.json b/server/tck/src/test/resources/tests/federation/output.json new file mode 100644 index 000000000..a95b4f97f --- /dev/null +++ b/server/tck/src/test/resources/tests/federation/output.json @@ -0,0 +1,24 @@ +{ + "data": { + "deepList": [ + [ + [ + { + "names": [ + "Phillip" + ] + } + ] + ] + ], + "deepListFoo": [ + [ + [ + { + "bar": "bar" + } + ] + ] + ] + } +} \ No newline at end of file diff --git a/server/tck/src/test/resources/tests/federation/test.properties b/server/tck/src/test/resources/tests/federation/test.properties new file mode 100644 index 000000000..db74c7f9b --- /dev/null +++ b/server/tck/src/test/resources/tests/federation/test.properties @@ -0,0 +1,2 @@ +ignore=false +priority=100