Federatiivisten aligraafien rakentaminen
Kehittäkää yksittäisiä Spring Boot -palveluja federatiivisina aligraafeina ja määritelkää niiden skeemat ja entiteettisuhteet.
Federatiivisten aligraafien rakentaminen on ilmainen GraphQL-rajapinnat Spring Bootilla-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu GraphQL-rajapinnat Spring Bootilla-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. GraphQL-rajapinnat Spring Bootilla-kurssilla on yhteensä 4 oppituntia.
Johdatus federoituihin alikaavioihin
GraphQL Federationissa supergraafi koostuu useista itsenäisistä GraphQL-palveluista, joita kutsutaan alikaavioiksi.
Kukin alikaavio on itsenäinen GraphQL-rajapinta, joka omistaa tietyn osan toimialueen mallista. Ajattele sitä datastasi vastaavana mikropalveluna.
Apollo Gateway yhdistää nämä alikaaviot yhdeksi yhtenäiseksi rajapinnaksi, joten asiakkaiden on helppo tehdä kyselyitä eri palveluiden tietoihin.
Federoitujen entiteettien ymmärtäminen
Entiteetit ovat alikaavioiden yhdistämisen keskeinen käsite. Entiteetti edustaa tyyppiä, johon voidaan viitata ja jota voidaan laajentaa eri palveluissa.
Esimerkiksi User-entiteetti voidaan määritellä "Auth"-alikaaviossa, mutta "Product"-alikaavio voi laajentaa sitä lisäämällä käyttäjäkohtaisia arvosteluja.
Entiteetit merkitään skeemaan @key-direktiivillä, joka määrittää, miten kyseisen tyypin ilmentymä yksilöidään.
Alikaavion määrittäminen
Federoidun alikaavion rakentaminen Spring Bootilla alkaa tavallisesta Spring Boot GraphQL -projektista.
Keskeinen riippuvuus on spring-boot-starter-graphql. Varmista, että mukana on myös HTTP-päätepisteisiin tarvittava spring-boot-starter-web.
Lisäksi sinun on määritettävä build.gradle- tai pom.xml-tiedosto niin, että se sisältää GraphQL-skeematiedostot (.graphqls).
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'
}
Skeema ja @key-direktiivi
@key-direktiivi on ratkaisevan tärkeä. Se kertoo Apollo Gatewaylle, mitkä kentät yksilöivät entiteetin alikaaviossasi.
Voit määrittää useita avaimia tai yhdistelmäavaimia (esimerkiksi @key(fields: "id type")). Gateway käyttää näitä kenttiä noutaessaan osittaisia tietoja muista alikaavioista.
Määritellään yksinkertainen Product-entiteetti ja merkitään sen id ensisijaiseksi avaimeksi.
# 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!
}Product-entiteetin rakentaminen
Toteutetaan nyt Product-entiteetti Spring Boot -sovelluksessamme. Tämä edellyttää dataluokan ja resolverin luomista.
Resolver käsittelee tuotteita koskevat kyselyt kuten mikä tahansa GraphQL-päätepiste. Käytämme yksinkertaisuuden vuoksi muistissa säilytettävää dataa.
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; }
}
}_entities-resolverin toteuttaminen
Apollo Gateway tarvitsee tavan pyytää alikaavioltasi entiteettiä sen avaimen perusteella. Tämä hoidetaan erityisellä _entities-kyselyllä.
Spring Bootissa toteutat tämän tarjoamalla RuntimeWiringConfigurer-beanin. Tämä bean yhdistää _entities-kyselyn datan noutajaan.
Datan noutaja vastaanottaa "representations"-esityksiä (karttoja, jotka sisältävät __typename- ja avainkentät) ja palauttaa vastaavat entiteettioliot.
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; }
}
}Omistamasi entiteetin laajentaminen
Jos alikaaviosi omistaa entiteetin eli määritteli @key-direktiivin, voit lisätä siihen kenttiä päivittämällä sen skeemaa ja resolveria.
Nämä uudet kentät ovat suoraan saatavilla alikaaviostasi. Gateway tietää, että näitä kenttiä koskevat kyselyt on reititettävä palveluusi.
Lisätään description-kenttä Product-entiteettiimme.
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());
})
);
}
}Ulkoisten entiteettien laajentaminen
Mitä jos toinen alikaavio määrittelee Product-entiteetin, mutta alikaaviosi, esimerkiksi "Review"-palvelu, haluaa lisätä siihen arvosteluja?
Käytät tyyppimäärityksessä @extends-direktiiviä. Se kertoo Gatewaylle, että tämä tyyppi on muualla määritellyn entiteetin laajennus.
Käytät myös @external-direktiiviä kentissä, jotka kuuluvat alkuperäiseen entiteettimääritykseen mutta joita alikaaviosi tarvitsee uusien kenttien ratkaisemiseen.
# 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
}Laajennettujen kenttien ratkaiseminen
Kun alikaaviosi laajentaa entiteettiä, sinun on toteutettava resolver lisäämillesi uusille kentille, kuten Product-entiteetin reviews-kentälle.
Spring GraphQL käyttää tähän @SchemaMapping-annotaatiota. Metodi vastaanottaa pääolio-olion (Product-instanssin), joka sisältää @external-kentät.
Gateway välittää id-kentän (meidän @external-kenttämme) resolverille, joten voit noutaa asiaankuuluvat arvostelut.
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
}Direktiivien testi
Federation perustuu vahvasti tiettyihin direktiiveihin, jotka määrittävät, miten alikaaviot toimivat yhdessä. Testaa, miten hyvin hallitset nämä keskeiset direktiivit.
Alikaavioiden rakentamisen kertaus
Olet oppinut rakentamaan federoituja alikaavioita Spring Bootilla!
- Entiteettien määrittäminen
@key-direktiivillä. _entities-resolverien toteuttaminen, jotta Gateway voi noutaa entiteettejä.- Kenttien lisääminen alikaaviosi omistamiin entiteetteihin.
- Muiden alikaavioiden entiteettien laajentaminen direktiiveillä
@extendsja@external. - Resolverien toteuttaminen näille laajennetuille kentille
@SchemaMapping-annotaation avulla.
Näiden rakennuspalikoiden avulla voit luoda modulaarisia ja skaalautuvia GraphQL-rajapintoja Federationilla.
Opi GraphQL-rajapinnat Spring Bootilla tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 12
- Oppitunnit
- 48
Usein kysytyt kysymykset
Onko oppitunti ”Federatiivisten aligraafien rakentaminen” ilmainen?
Kyllä – oppitunnin ”Federatiivisten aligraafien rakentaminen” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko GraphQL-rajapinnat Spring Bootilla-kurssin, päivitä CoddyKit PROhon. GraphQL-rajapinnat Spring Bootilla-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Federatiivisten aligraafien rakentaminen”?
Kehittäkää yksittäisiä Spring Boot -palveluja federatiivisina aligraafeina ja määritelkää niiden skeemat ja entiteettisuhteet. Harjoittelet GraphQL-rajapinnat Spring Bootilla-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni GraphQL-rajapinnat Spring Bootilla-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin GraphQL-rajapinnat Spring Bootilla-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.
Kuinka kauan ”Federatiivisten aligraafien rakentaminen”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä GraphQL-rajapinnat Spring Bootilla-oppitunnilla?
Kyllä. Jokainen GraphQL-rajapinnat Spring Bootilla-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Apollo Federationin esittely
- Federatiivisten aligraafien rakentaminen
- Gatewayn määrittäminen ja hallinta
- Entiteettiviitteet ja @key-direktiivi