Gefedereerde subgraphs bouwen
Ontwikkel afzonderlijke Spring Boot-services als gefedereerde subgraphs en definieer hun schema en entiteitsrelaties.
Gefedereerde subgraphs bouwen is een gratis GraphQL-API's met Spring Boot-les op CoddyKit. Dit is les 2 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject GraphQL-API's met Spring Boot. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus GraphQL-API's met Spring Boot bevat in totaal 4 lessen.
Inleiding tot federatieve deelgrafen
In GraphQL Federation bestaat een supergraaf uit meerdere onafhankelijke GraphQL-services, die deelgrafen worden genoemd.
Elke deelgraaf is een zelfstandige GraphQL-API die verantwoordelijk is voor een specifiek deel van je domeinmodel. Zie het als een microservice voor je gegevens.
De Apollo Gateway combineert deze deelgrafen vervolgens tot één uniforme API, zodat clients eenvoudig gegevens uit verschillende services kunnen opvragen.
Federatieve entiteiten begrijpen
Entiteiten vormen het kernconcept voor het verbinden van deelgrafen. Een entiteit stelt een type voor waarnaar in verschillende services kan worden verwezen en dat daar kan worden uitgebreid.
Een User-entiteit kan bijvoorbeeld in een deelgraaf met de naam "Auth" worden gedefinieerd en door een deelgraaf met de naam "Product" worden uitgebreid met gebruikersspecifieke beoordelingen.
Entiteiten worden in het schema gemarkeerd met de @key-directief, die bepaalt hoe een exemplaar van dat type uniek wordt geïdentificeerd.
Je deelgraaf instellen
Om met Spring Boot een federatieve deelgraaf te bouwen, begin je met een standaard Spring Boot GraphQL-project.
De belangrijkste afhankelijkheid is spring-boot-starter-graphql. Zorg er ook voor dat je spring-boot-starter-web toevoegt voor HTTP-eindpunten.
Je moet ook je build.gradle of pom.xml configureren om GraphQL-schemabestanden (.graphqls) op te nemen.
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.5'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'com.coddykit'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-graphql'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework:spring-graphql-test'
}
Schema met de @key-directief
De @key-directief is cruciaal. Deze vertelt de Apollo Gateway welke velden een entiteit binnen je deelgraaf uniek identificeren.
Je kunt meerdere sleutels of samengestelde sleutels definiëren, bijvoorbeeld @key(fields: "id type"). De gateway gebruikt deze velden om gedeeltelijke gegevens uit andere deelgrafen op te halen.
Laten we een eenvoudige Product-entiteit definiëren en het veld id als primaire sleutel markeren.
# src/main/resources/graphql/schema.graphqls
type Query {
products: [Product]
productById(id: ID!): Product
}
type Product @key(fields: "id") {
id: ID!
name: String!
price: Float!
}De Product-entiteit bouwen
Nu gaan we de Product-entiteit implementeren in onze Spring Boot-toepassing. Hiervoor maken we een gegevensklasse en een resolver.
De resolver verwerkt query's voor producten, net als elk ander GraphQL-eindpunt. Voor de eenvoud gebruiken we gegevens in het geheugen.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
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.ArrayList;
// Assume schema.graphqls is defined as in Scene 4
@SpringBootApplication
public class ProductSubgraphApplication {
public static void main(String[] args) {
SpringApplication.run(ProductSubgraphApplication.class, args);
}
@Controller
public static class ProductResolver {
private static final List<Product> products = new ArrayList<>(List.of(
new Product("1", "Laptop", 1200.00),
new Product("2", "Mouse", 25.00)
));
@QueryMapping
public List<Product> products() {
return products;
}
@QueryMapping
public Product productById(@Argument String id) {
return products.stream()
.filter(p -> p.getId().equals(id))
.findFirst()
.orElse(null);
}
}
public static class Product {
private String id;
private String name;
private Double price;
public Product(String id, String name, Double price) {
this.id = id;
this.name = name;
this.price = price;
}
public String getId() { return id; }
public String getName() { return name; }
public Double getPrice() { return price; }
}
}De _entities-resolver implementeren
De Apollo Gateway heeft een manier nodig om je deelgraaf op basis van de sleutel om een entiteit te vragen. Dit gebeurt met een speciale _entities-query.
In Spring Boot implementeer je dit door een bean van het type RuntimeWiringConfigurer aan te bieden. Deze bean koppelt de _entities-query aan een gegevensophaler.
De gegevensophaler ontvangt "representations" (toewijzingen van __typename en sleutelvelden) en moet de bijbehorende entiteitsobjecten retourneren.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import graphql.schema.idl.RuntimeWiring;
import org.springframework.graphql.execution.RuntimeWiringConfigurer;
import org.springframework.stereotype.Controller;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.ArrayList;
// Assume schema.graphqls and Product/ProductResolver from Scene 5
@SpringBootApplication
public class ProductSubgraphApplication { // Same as previous scene
public static void main(String[] args) {
SpringApplication.run(ProductSubgraphApplication.class, args);
}
@Bean
public RuntimeWiringConfigurer runtimeWiringConfigurer() {
return builder -> builder.type("Query", typeWiring ->
typeWiring.dataFetcher("_entities", env -> {
List<Map<String, Object>> representations = env.getArgument("representations");
return representations.stream()
.map(representation -> {
if ("Product".equals(representation.get("__typename"))) {
String id = (String) representation.get("id");
// In a real app, fetch from DB by ID
return new Product(id, "Product " + id + " (Federated)", 0.0);
}
return null;
})
.collect(Collectors.toList());
})
);
}
// ProductResolver and Product class from Scene 5 would be here
@Controller
public static class ProductResolver {
private static final List<Product> products = new ArrayList<>(List.of(
new Product("1", "Laptop", 1200.00),
new Product("2", "Mouse", 25.00)
));
@QueryMapping public List<Product> products() { return products; }
@QueryMapping public Product productById(String id) {
return products.stream().filter(p -> p.getId().equals(id)).findFirst().orElse(null);
}
}
public static class Product {
private String id; private String name; private Double price;
public Product(String id, String name, Double price) { this.id=id; this.name=name; this.price=price; }
public String getId() { return id; } public String getName() { return name; }
public Double getPrice() { return price; }
}
}Je eigen entiteit uitbreiden
Als je deelgraaf eigenaar is van een entiteit, wat betekent dat deze de @key heeft gedefinieerd, kun je er eenvoudig meer velden aan toevoegen door het schema en de resolver bij te werken.
Deze nieuwe velden zijn rechtstreeks beschikbaar vanuit je deelgraaf. De gateway weet dat query's voor deze velden naar jouw service moeten worden gerouteerd.
Laten we een veld description toevoegen aan onze Product-entiteit.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import org.springframework.context.annotation.Bean;
import graphql.schema.idl.RuntimeWiring;
import org.springframework.graphql.execution.RuntimeWiringConfigurer;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.ArrayList;
// src/main/resources/graphql/schema.graphqls (updated)
// type Product @key(fields: "id") {
// id: ID!
// name: String!
// price: Float!
// description: String # NEW FIELD
// }
// ... (rest of schema and _entities resolver as before)
@SpringBootApplication
public class ProductSubgraphApplication { // Same as previous scene
public static void main(String[] args) {
SpringApplication.run(ProductSubgraphApplication.class, args);
}
@Controller
public static class ProductResolver {
private static final List<Product> products = new ArrayList<>(List.of(
new Product("1", "Laptop", 1200.00, "Powerful computing device."),
new Product("2", "Mouse", 25.00, "Ergonomic wireless mouse.")
));
@QueryMapping public List<Product> products() { return products; }
@QueryMapping public Product productById(String id) {
return products.stream().filter(p -> p.getId().equals(id)).findFirst().orElse(null);
}
}
public static class Product {
private String id; private String name; private Double price; private String description; // NEW FIELD
public Product(String id, String name, Double price, String description) {
this.id = id; this.name = name; this.price = price; this.description = description;
}
public String getId() { return id; } public String getName() { return name; }
public Double getPrice() { return price; } public String getDescription() { return description; }
}
// runtimeWiringConfigurer bean would be here as in Scene 6
@Bean
public RuntimeWiringConfigurer runtimeWiringConfigurer() {
return builder -> builder.type("Query", typeWiring ->
typeWiring.dataFetcher("_entities", env -> {
List<Map<String, Object>> representations = env.getArgument("representations");
return representations.stream()
.map(representation -> {
if ("Product".equals(representation.get("__typename"))) {
String id = (String) representation.get("id");
// Fetch full product data based on ID
return new Product(id, "Product " + id, 0.0, "Placeholder desc.");
}
return null;
})
.collect(Collectors.toList());
})
);
}
}Externe entiteiten uitbreiden
Wat doe je als een andere deelgraaf Product definieert, maar jouw deelgraaf, bijvoorbeeld een service met de naam "Review", er beoordelingen aan wil toevoegen?
Je gebruikt de @extends-directief in de typedefinitie. Daarmee vertel je de gateway dat dit type een uitbreiding is van een elders gedefinieerde entiteit.
Je gebruikt ook @external voor velden die deel uitmaken van de oorspronkelijke entiteitsdefinitie, maar die je deelgraaf nodig heeft om zijn nieuwe velden op te lossen.
# src/main/resources/graphql/schema.graphqls (Review Subgraph)
type Query {
reviews: [Review]
}
type Review {
id: ID!
text: String!
productId: ID!
}
# This subgraph extends the Product type from another service
extend type Product @key(fields: "id") {
id: ID! @external
reviews: [Review] # New field added by THIS subgraph
}Uitgebreide velden oplossen
Wanneer je deelgraaf een entiteit uitbreidt, moet je een resolver implementeren voor de nieuwe velden die je hebt toegevoegd, bijvoorbeeld reviews op Product.
Spring GraphQL gebruikt hiervoor de annotatie @SchemaMapping. De methode ontvangt het bovenliggende object, de Product-instantie, dat de velden met @external bevat.
De gateway geeft het veld id, ons veld met @external, door aan je resolver, zodat je de relevante beoordelingen kunt ophalen.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.graphql.data.method.annotation.SchemaMapping; // Important for extensions
import org.springframework.stereotype.Controller;
import org.springframework.context.annotation.Bean;
import graphql.schema.idl.RuntimeWiring;
import org.springframework.graphql.execution.RuntimeWiringConfigurer;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.ArrayList;
// Assume schema.graphqls is defined as in Scene 8
@SpringBootApplication
public class ReviewSubgraphApplication {
public static void main(String[] args) {
SpringApplication.run(ReviewSubgraphApplication.class, args);
}
@Controller
public static class ReviewResolver {
private static final List<Review> reviews = new ArrayList<>(List.of(
new Review("101", "Great laptop!", "1"),
new Review("102", "Mouse works well.", "2"),
new Review("103", "Solid performance.", "1")
));
@QueryMapping
public List<Review> reviews() {
return reviews;
}
// Resolver for the 'reviews' field on the extended Product type
@SchemaMapping(typeName = "Product")
public List<Review> reviews(Product product) { // Product object will have its 'id'
return reviews.stream()
.filter(r -> r.getProductId().equals(product.getId()))
.collect(Collectors.toList());
}
}
public static class Review {
private String id; private String text; private String productId;
public Review(String id, String text, String productId) {
this.id = id; this.text = text; this.productId = productId;
}
public String getId() { return id; } public String getText() { return text; }
public String getProductId() { return productId; }
}
// Product class for extensions (only needs @external fields)
public static class Product {
private String id; // This field is received from Gateway
public Product(String id) { this.id = id; }
public String getId() { return id; }
}
// _entities resolver for Review type (if Review is also an entity) would be here if needed
}Controle van directieven
Federation maakt intensief gebruik van specifieke directieven om te definiëren hoe deelgrafen samenwerken. Test je begrip van deze belangrijke directieven.
Samenvatting van het bouwen van deelgrafen
Je hebt geleerd hoe je federatieve deelgrafen bouwt in Spring Boot!
- Entiteiten definiëren met de
@key-directief. _entities-resolvers implementeren zodat de gateway entiteiten kan ophalen.- Velden toevoegen aan entiteiten waarvan je deelgraaf eigenaar is.
- Entiteiten uit andere deelgrafen uitbreiden met
@extendsen@external. - Resolvers implementeren voor deze uitgebreide velden met
@SchemaMapping.
Met deze bouwstenen kun je modulaire en schaalbare GraphQL-API's met Federation maken.
Leer GraphQL-API's met Spring Boot met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 12
- Lessen
- 48
Veelgestelde vragen
Is de les “Gefedereerde subgraphs bouwen” gratis?
Ja — de volledige tekst van “Gefedereerde subgraphs bouwen” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus GraphQL-API's met Spring Boot wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus GraphQL-API's met Spring Boot bevat in totaal 4 lessen.
Wat leer ik in “Gefedereerde subgraphs bouwen”?
Ontwikkel afzonderlijke Spring Boot-services als gefedereerde subgraphs en definieer hun schema en entiteitsrelaties. Je oefent met GraphQL-API's met Spring Boot door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met GraphQL-API's met Spring Boot te beginnen?
Ervaring vooraf is niet nodig. GraphQL-API's met Spring Boot op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.
Hoe lang duurt de les “Gefedereerde subgraphs bouwen”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over GraphQL-API's met Spring Boot?
Ja. Elke les over GraphQL-API's met Spring Boot bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Kennismaken met Apollo Federation
- Gefedereerde subgraphs bouwen
- Gateway instellen en beheren
- Entity-referenties en de @key-directive