Skip to content

Commit

Permalink
Upgrade to Spring for GraphQL 1.3 and use built-in federation support (
Browse files Browse the repository at this point in the history
…#80)

Spring for GraphQL 1.3 adds [built-in federation support](https://spring.io/blog/2024/02/21/spring-for-graphql-1-3-m1-released#apollo-federation) with annotated, controller methods. This PR contains the changes to switch to the built-in support. Also some minor refactoring.

I know 1.3 is not due until May 21, and Spring Boot 3.3 until May 23, but I wanted to have the changes ready and make sure all works as expected. For now this is based on release candidates.
  • Loading branch information
rstoyanchev authored May 1, 2024
1 parent f88fbb2 commit ed6b7a6
Show file tree
Hide file tree
Showing 16 changed files with 122 additions and 103 deletions.
3 changes: 2 additions & 1 deletion products-subgraph/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import org.springframework.boot.gradle.tasks.bundling.BootJar

plugins {
id("org.springframework.boot") version "3.1.4"
id("org.springframework.boot") version "3.3.0-RC1"
id("io.spring.dependency-management") version "1.1.3"
java
}
Expand All @@ -11,6 +11,7 @@ version = "0.0.1-SNAPSHOT"

repositories {
mavenCentral()
maven("https://repo.spring.io/milestone")
}

val federation_jvm_version: String = project.property("federation-jvm.version").toString()
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.graphql.GraphQlSourceBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.graphql.data.federation.FederationSchemaFactory;

@SpringBootApplication
public class ProductsApplication {
Expand All @@ -10,4 +13,14 @@ public static void main(String[] args) {
SpringApplication.run(ProductsApplication.class, args);
}

@Bean
public GraphQlSourceBuilderCustomizer customizer(FederationSchemaFactory factory) {
return builder -> builder.schemaFactory(factory::createGraphQLSchema);
}

@Bean
FederationSchemaFactory federationSchemaFactory() {
return new FederationSchemaFactory();
}

}
Original file line number Diff line number Diff line change
@@ -1,34 +1,25 @@
package com.example.products;

import java.util.List;

import com.example.products.model.Product;
import com.example.products.model.ProductSource;

import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Controller
public class ProductsController {

private final Map<String, Product> PRODUCTS = Stream.of(
new Product("1","Saturn V", "The Original Super Heavy-Lift Rocket!"),
new Product("2","Lunar Module"),
new Product("3","Space Shuttle"),
new Product("4","Falcon 9", "Reusable Medium-Lift Rocket"),
new Product("5","Dragon", "Reusable Medium-Lift Rocket"),
new Product("6","Starship", "Super Heavy-Lift Reusable Launch Vehicle")
).collect(Collectors.toMap(Product::id, product -> product));

@QueryMapping
public Product product(@Argument String id) {
return PRODUCTS.get(id);
public Product product(@Argument Long id) {
return ProductSource.getProduct(id);
}

@QueryMapping
public List<Product> products() {
return PRODUCTS.values().stream().toList();
return ProductSource.getProducts();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
* description: String
* }
*/
public record Product(String id, String name, String description) {
public record Product(Long id, String name, String description) {

public Product(String id, String name) {
public Product(Long id, String name) {
this(id, name, null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.example.products.model;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public final class ProductSource {

private static final List<Product> productList = List.of(
new Product(1L, "Saturn V", "The Original Super Heavy-Lift Rocket!"),
new Product(2L, "Lunar Module"),
new Product(3L, "Space Shuttle"),
new Product(4L, "Falcon 9", "Reusable Medium-Lift Rocket"),
new Product(5L, "Dragon", "Reusable Medium-Lift Rocket"),
new Product(6L, "Starship", "Super Heavy-Lift Reusable Launch Vehicle")
);

private static final Map<Long, Product> productMap =
productList.stream().collect(Collectors.toMap(Product::id, product -> product));

public static Product getProduct(Long id) {
return productMap.get(id);
}

public static List<Product> getProducts() {
return productList;
}

}
3 changes: 3 additions & 0 deletions products-subgraph/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ spring:
graphql:
graphiql:
enabled: true
logging:
level:
org.springframework.graphql: DEBUG
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ query ProductById($productId: ID!) {
.execute()
.path("product")
.entity(Product.class)
.isEqualTo(new Product("1","Saturn V", "The Original Super Heavy-Lift Rocket!"));
.isEqualTo(new Product(1L,"Saturn V", "The Original Super Heavy-Lift Rocket!"));
}
}
3 changes: 2 additions & 1 deletion reviews-subgraph/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import org.springframework.boot.gradle.tasks.bundling.BootJar

plugins {
id("org.springframework.boot") version "3.1.4"
id("org.springframework.boot") version "3.3.0-RC1"
id("io.spring.dependency-management") version "1.1.3"
java
}
Expand All @@ -11,6 +11,7 @@ version = "0.0.1-SNAPSHOT"

repositories {
mavenCentral()
maven("https://repo.spring.io/milestone")
}

val federation_jvm_version: String = project.property("federation-jvm.version").toString()
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.graphql.GraphQlSourceBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.graphql.data.federation.FederationSchemaFactory;

@SpringBootApplication
public class ReviewsApplication {
Expand All @@ -10,4 +13,14 @@ public static void main(String[] args) {
SpringApplication.run(ReviewsApplication.class, args);
}

@Bean
public GraphQlSourceBuilderCustomizer customizer(FederationSchemaFactory factory) {
return builder -> builder.schemaFactory(factory::createGraphQLSchema);
}

@Bean
FederationSchemaFactory federationSchemaFactory() {
return new FederationSchemaFactory();
}

}
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
package com.example.reviews;

import com.example.reviews.model.Review;
import java.util.List;

import com.example.reviews.model.Product;
import com.example.reviews.model.Review;
import com.example.reviews.model.ReviewSource;

import org.springframework.graphql.data.federation.EntityMapping;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.SchemaMapping;
import org.springframework.stereotype.Controller;

import java.util.Collections;
import java.util.List;
import java.util.Map;

@Controller
public class ReviewsController {

private final Map<String, List<Review>> REVIEWS = Map.of(
"2", List.of(new Review("1020", "Very cramped :( Do not recommend.", 2), new Review("1021", "Got me to the Moon!", 4)),
"3", List.of(new Review("1030", 3)),
"4", List.of(new Review("1040", 5), new Review("1041", "Reusable!", 5), new Review("1042", 5)),
"5", List.of(new Review("1050", "Amazing! Would Fly Again!", 5), new Review("1051", 5))
);
@EntityMapping
public Product product(@Argument Long id) {
return new Product(id);
}

@SchemaMapping
public List<Review> reviews(Product show) {
return REVIEWS.getOrDefault(show.id(), Collections.emptyList());
public List<Review> reviews(Product product) {
return ReviewSource.getReviews(product);
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.example.reviews.model;

public record Product(String id) {
public record Product(Long id) {
public static final String PRODUCT_TYPE = "Product";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.example.reviews.model;

import java.util.Collections;
import java.util.List;
import java.util.Map;

public final class ReviewSource {

private static final Map<Long, List<Review>> reviewMap = Map.of(
2L, List.of(new Review("1020", "Very cramped :( Do not recommend.", 2), new Review("1021", "Got me to the Moon!", 4)),
3L, List.of(new Review("1030", 3)),
4L, List.of(new Review("1040", 5), new Review("1041", "Reusable!", 5), new Review("1042", 5)),
5L, List.of(new Review("1050", "Amazing! Would Fly Again!", 5), new Review("1051", 5))
);

public static List<Review> getReviews(Product product) {
return reviewMap.getOrDefault(product.id(), Collections.emptyList());
}

}
7 changes: 6 additions & 1 deletion reviews-subgraph/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@ spring:
graphql:
graphiql:
enabled: true

schema:
printer:
enabled: true
logging:
level:
org.springframework.graphql: DEBUG
8 changes: 8 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
pluginManagement {
repositories {
mavenCentral()
gradlePluginPortal()
maven("https://repo.spring.io/milestone")
}
}

rootProject.name = "federation-jvm-spring-example"

include(":products-subgraph")
Expand Down

0 comments on commit ed6b7a6

Please sign in to comment.