Entity Resolution Patterns
Techniques for orchestrating entities with Apollo Connectors
Apollo Connectors let you create and complete entities by combining data from multiple endpoints.
Combining endpoints to complete an entity
Connectors can orchestrate multiple endpoints to provide a unified representation of a type.
For example, you may want to combine product data from a /products endpoint that provides a few fields for all products and a /products/:id endpoint that provides more fields, specifically product variant information, for a single product.
1type Query {
2 products: [Product]
3 @connect(
4 source: "ecomm"
5 http: { GET: "/products" }
6 selection: """
7 $.products {
8 id
9 name
10 description
11 }
12 """
13 )
14}
15
16type Product
17 @connect(
18 source: "ecomm"
19 http: { GET: "/products/{$this.id}" }
20 selection: """
21 id
22 name
23 description
24 variants {
25 id: variantID
26 name
27 }
28 """
29) {
30 id: ID!
31 name: String
32 description: String
33 variants: [Variant]
34}
35
36type Variant {
37 id: ID!
38 name: String
39}How does the router handle this query?
query ListProductsAndVariants {
products {
id
name
variants {
id
name
}
}
}Combining representations of the same type with multiple Connectors
You can add multiple Connectors to the same field, and the GraphOS Router chooses to call one or both depending on the fields in the client query. This is especially useful when you have multiple API versions.
type Product
@connect(
source: "ecomm"
http: { GET: "/v1/products/{$this.id}" }
selection: """
id
color
"""
)
@connect(
source: "ecomm"
http: { GET: "/v2/products/{$this.id}" }
selection: """
id
name
price
variants {
id: variantID
color
}
"""
)
{
id: ID!
name: String
price: Int
color: String @deprecated(reason: "Use the 'variants' field instead")
variants: [Variant]
}
type Variant {
id: ID!
color: String
}Efficiently fetching additional information
If you provide the GraphOS Router with multiple Connectors that fetch additional information, it can choose the optimal endpoint to resolve the requested fields.
For example, if the client operation requests the reviews field, the GraphOS Router chooses the second Connector to fetch the reviews along with the product details.
type Product
@connect(
source: "ecomm"
http: { GET: "/products/{$this.id}" }
selection: """
id
name
price
"""
)
@connect(
source: "ecomm"
http: { GET: "/products/{$this.id}?include=reviews" }
selection: """
id
name
price
reviews {
id
rating
comment
}
"""
)
{
id: ID!
name: String
price: Int
reviews: [Review]
}
type Review {
id: ID!
rating: Float
comment: String
}Nullable entity references
The ? operator indicates that the expression to its left can be null or None. If the expression is null, the statement short-circuits and evaluates to None. Otherwise, the statement continues to execute.
1a: b?.c # If `b` is `null` or `None`, `a` becomes `None`. Otherwise, `a` becomes the value of `b.c`
2a: b?->c # If `b` is `null` or `None`, `a` becomes `None`. Otherwise, `a` becomes the value of `b->c`
3a: b? { c } # If `b` is `null` or `None`, `a` becomes `None`. Otherwise, `a` becomes the value of `b { c }`If an entity reference is optional, you can express this by making the sub-selection optional:
1author: authorId? {
2 id: @
3}
4
5# Shorthand if the field name is the same as the mapped name
6author? { id: @ }Additional resources
To learn how to use entities across different subgraphs in a federated schema, see Working with entities across subgraphs
To learn more about batching entity requests, see Batching requests