Resolve another subgraph's fields
Resolve the same entity field from different subgraphs
By default, exactly one subgraph resolves each field in your supergraph schema, with exceptions like entity @key
fields.
Sometimes, multiple subgraphs can resolve a specific entity field because they share access to a data store.
For example, an Inventory subgraph and a Products subgraph might both have access to the same database that stores all product-related data.
This guide explains how you can enable different subgraphs to resolve the same field as a performance optimization.
Enable subgraphs to resolve the same field
You can optionally enable multiple subgraphs to resolve a particular entity field. Then, when the router plans a query's execution, it looks at which fields are available from each subgraph. The router can optimize performance by executing the query across the fewest subgraphs needed.
To do this, use one of the following directives:
@shareable
@provides
Which directive you use depends on the following logic:
If you aren't sure whether your subgraph can always resolve a field, see Using @provides
for an example of a subgraph that can't.
Ensure resolver consistency
If multiple subgraphs can resolve a field, ensure each subgraph's resolver behaves identically for that field. Otherwise, queries might return inconsistent results to clients depending on which subgraph resolves the field.
This consistency is especially important to enforce when changing an existing resolver. Clients might observe inconsistent results if you don't make the resolver changes to each subgraph simultaneously.
Common inconsistent resolver behaviors to look out for include:
- Returning a different default value
- Throwing different errors in the same scenario
Using @shareable
ⓘ NOTE
Before using @shareable
, see Ensure resolver consistency.
The @shareable
directive indicates that more than one subgraph can resolve a particular field.
You can use it like so:
type Product @key(fields: "id") {id: ID!name: String! @shareableprice: Int}
type Product @key(fields: "id") {id: ID!name: String! @shareableinStock: Boolean!}
In this example, both the Products and Inventory subgraphs can resolve Product.name
.
That means queries including Product.name
can sometimes be resolved with fewer subgraph fetches.
ⓘ NOTE
If a field is marked @shareable
in any subgraph, it must be marked @shareable
or @external
in every subgraph that defines it. Otherwise, composition fails.
Using @provides
ⓘ NOTE
Before using @provides
, see Ensure resolver consistency.
The @provides
directive indicates that a particular field can be resolved by a subgraph at a particular query path.
For example, suppose the Inventory subgraph can resolve Product.name
, but only when that product is part of an InStockCount
.
You can indicate this like so:
type InStockCount {product: Product! @provides(fields: "name")quantity: Int!}type Product @key(fields: "id") {id: ID!name: String! @externalinStock: Boolean!}
Notice the Inventory subgraph uses two directives:
- The
@provides
directive tells the router, "This subgraph can resolve thename
of anyProduct
object returned byInStockCount.product
." - The
@external
directive tells the router, "This subgraph can't resolve thename
of aProduct
object, except wherever indicated by@provides
."
Rules for using @provides
ⓘ NOTE
Violating any of these rules causes composition to fail.
- If a subgraph
@provides
a field that it can't always resolve, the subgraph must mark that field as@external
and must not mark it as@shareable
.- Remember, a
@shareable
field can always be resolved by a particular subgraph, which removes the need for@provides
.
- Remember, a
- To include a field in a
@provides
directive, that field must be marked as@shareable
or@external
in every subgraph that defines it.