Federated Schemas
Learn about the different types of GraphQL schemas
A federated supergraph uses multiple "types" of GraphQL schemas:
Subgraph schemas. Each subgraph has a distinct schema that indicates which types and fields of your composed supergraph it can resolve.
These are the only schemas that your teams define manually.
Supergraph schema. This schema combines all of the types and fields from your subgraph schemas, plus some federation-specific information that tells your router which subgraphs can resolve which fields.
This schema is the result of performing composition on your collection of subgraph schemas.
API schema. This schema is similar to the supergraph schema, but it omits federation-specific types, fields, and directives that are considered "machinery" and are not part of your public API.
This is the schema that your router exposes to clients, which don't need to know internal implementation details about your graph.
Let's look at an example!
Subgraph schemas
Below are example schemas for three subgraphs in an e-commerce company's supergraph. Each subgraph is implemented as a separate GraphQL API:
1type Query {
2 me: User
3}
4
5type User @key(fields: "id") {
6 id: ID!
7 username: String! @shareable
8}
9
10# (Subgraph schemas include
11# this to opt in to
12# Federation 2 features.)
13extend schema
14 @link(url: "https://specs.apollo.dev/federation/v2.3",
15 import: ["@key", "@shareable"])
1type Query {
2 topProducts(first: Int = 5): [Product]
3}
4
5type Product @key(fields: "upc") {
6 upc: String!
7 name: String!
8 price: Int
9}
10
11extend schema
12 @link(url: "https://specs.apollo.dev/federation/v2.3",
13 import: ["@key", "@shareable"])
1type Review {
2 body: String
3 author: User @provides(fields: "username")
4 product: Product
5}
6
7type User @key(fields: "id") {
8 id: ID!
9 username: String! @external
10 reviews: [Review]
11}
12
13type Product @key(fields: "upc") {
14 upc: String!
15 reviews: [Review]
16}
17
18# (This subgraph uses additional
19# federated directives)
20extend schema
21 @link(url: "https://specs.apollo.dev/federation/v2.3",
22 import: ["@key", "@shareable", "@provides", "@external"])
As these schemas show, multiple subgraphs can contribute unique fields to a single type. For example, the Products subgraph and the Reviews subgraph both contribute fields to the Product
type.
Supergraph schema
The supergraph schema is the output of schema composition . It serves the following purposes:
It provides your router with the name and endpoint URL for each of your subgraphs.
It includes all types and fields defined by all of your subgraphs.
It tells your router which of your subgraphs can resolve which GraphQL fields.
Here's the supergraph schema composed with the subgraph schemas above :
Click to expand
1schema
2 @link(url: "https://specs.apollo.dev/link/v1.0")
3 @link(url: "https://specs.apollo.dev/join/v0.3", for: EXECUTION)
4{
5 query: Query
6}
7
8directive @join__enumValue(graph: join__Graph!) repeatable on ENUM_VALUE
9
10directive @join__field(graph: join__Graph, requires: join__FieldSet, provides: join__FieldSet, type: String, external: Boolean, override: String, usedOverridden: Boolean) repeatable on FIELD_DEFINITION | INPUT_FIELD_DEFINITION
11
12directive @join__graph(name: String!, url: String!) on ENUM_VALUE
13
14directive @join__implements(graph: join__Graph!, interface: String!) repeatable on OBJECT | INTERFACE
15
16directive @join__type(graph: join__Graph!, key: join__FieldSet, extension: Boolean! = false, resolvable: Boolean! = true, isInterfaceObject: Boolean! = false) repeatable on OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT | SCALAR
17
18directive @join__unionMember(graph: join__Graph!, member: String!) repeatable on UNION
19
20directive @link(url: String, as: String, for: link__Purpose, import: [link__Import]) repeatable on SCHEMA
21
22scalar join__FieldSet
23
24enum join__Graph {
25 PRODUCTS @join__graph(name: "products", url: "http://localhost:4002/graphql")
26 REVIEWS @join__graph(name: "reviews", url: "http://localhost:4003/graphql")
27 USERS @join__graph(name: "users", url: "http://localhost:4001/graphql")
28}
29
30scalar link__Import
31
32enum link__Purpose {
33 """
34 `SECURITY` features provide metadata necessary to securely resolve fields.
35 """
36 SECURITY
37
38 """
39 `EXECUTION` features provide metadata necessary for operation execution.
40 """
41 EXECUTION
42}
43
44type Product
45 @join__type(graph: PRODUCTS, key: "upc")
46 @join__type(graph: REVIEWS, key: "upc")
47{
48 upc: String!
49 name: String! @join__field(graph: PRODUCTS)
50 price: Int @join__field(graph: PRODUCTS)
51 reviews: [Review] @join__field(graph: REVIEWS)
52}
53
54type Query
55 @join__type(graph: PRODUCTS)
56 @join__type(graph: REVIEWS)
57 @join__type(graph: USERS)
58{
59 topProducts(first: Int = 5): [Product] @join__field(graph: PRODUCTS)
60 me: User @join__field(graph: USERS)
61}
62
63type Review
64 @join__type(graph: REVIEWS)
65{
66 body: String
67 author: User @join__field(graph: REVIEWS, provides: "username")
68 product: Product
69}
70
71type User
72 @join__type(graph: REVIEWS, key: "id")
73 @join__type(graph: USERS, key: "id")
74{
75 id: ID!
76 username: String! @join__field(graph: REVIEWS, external: true) @join__field(graph: USERS)
77 reviews: [Review] @join__field(graph: REVIEWS)
78}
As you can see, the supergraph schema includes a lot of Federation-specific additions! These additions are used only by the router, and you'll never need to add them manually.
API schema
The router uses its supergraph schema to produce an API schema, which it exposes to clients as your actual GraphQL API. This schema cleanly and logically represents the combination of your subgraph schemas :
1type Product {
2 name: String!
3 price: Int
4 reviews: [Review]
5 upc: String!
6}
7
8type Query {
9 me: User
10 topProducts(first: Int = 5): [Product]
11}
12
13type Review {
14 author: User
15 body: String
16 product: Product
17}
18
19type User {
20 id: ID!
21 reviews: [Review]
22 username: String!
23}
Unlike the supergraph schema, this schema hides the fact that your GraphQL API is composed of multiple distinct GraphQL APIs.