Develop your graph with Connectors

Use your graph to orchestrate REST API calls with Apollo Connectors and Apollo Federation


In the previous guide, you set up a graph in GraphOS Studio and started a local dev session. In this guide, you will develop your graph by connecting live REST API endpoints to your graph using Apollo Connectors.

Let's start developing!

🧰 Meet your tools

In this guide you'll be using the following Apollo tools:

  • Apollo Sandbox is a local development tool lets you test requests, inspect and debug responses, and more.

  • Apollo Connectors are the quickest way to set up a graph backed by REST endpoints.




Connectors are a part of the GraphOS Router, the single point of entry for clients to your graph.

None of these tools requires a paid plan.

Develop your graph

In this step, you will:

  • Walk through an example GraphQL schema to learn how Connectors declaratively integrate REST APIs.

  • Make requests in Apollo Sandbox to observe how Connectors orchestrate calls to the connected REST APIs.

  • Create more Connectors from scratch, where each Connector demonstrates a different capability of Apollo Connectors.

Love developer tooling? 🛠️
Whether you're developing in VS Code, Vim/NeoVim, or with a JetBrains IDE, Apollo's got you covered with tooling for a better developer experience. Now is a great time to set up these plugins to get better autocomplete and faster feedback as you develop.

Explore example Connector

Let's take a look at the products.graphql GraphQL schema to see how Connectors work.

  1. The first few lines use @link directives to enable the latest versions of federation and Connectors.

    GraphQL
    products.graphql
    extend schema
      @link(
        url: "https://specs.apollo.dev/federation/v2.10"
        import: ["@key"]
      )
      @link(
        url: "https://specs.apollo.dev/connect/v0.1"
        import: ["@connect", "@source"]
      )
  2. In the next few lines, the @source directive creates a reusable configuration that each Connector can reference. In this case, it only sets the baseURL to the ecommerce demo API this guide uses. You can also add request headers to a @source.

    GraphQL
    products.graphql
      @source(
        name: "ecomm"
        http: { baseURL: "https://ecommerce.demo-api.apollo.dev/" }
      )
  3. Product is the standard object type the GraphQL API returns.

    GraphQL
    products.graphql
    type Product {
      id: ID!
      name: String
      description: String
    }
  4. The Query type has a products field that the @connect directive implements.

    What's the Query type?
    In a GraphQL schema, the Query type defines the entry points for reading data from a GraphQL schema. It acts as the root type that clients use to request specific fields and traverse the graph.
    GraphQL
    products.graphql
    type Query {
      products: [Product]
        # A @connect directive defines the API data source of a GraphQL schema field.
        @connect(
          source: "ecomm"
          http: { GET: "/products" }
          selection: """
          $.products {  
            id
            name
            description
          }
          """
        )
    }

    Here is what each of @connect's arguments does:

    • source: "ecomm" refers to the @source instance.

    • http sets the method (GET) and path (/products) for the request.

    • selection maps the REST API's JSON response to the fields in the GraphQL schema.

To understand how to map a JSON response to your GraphQL schema, you inspect the JSON response. Here's what the response for /products looks like:

/products
JSON
1{
2  "products": [
3    {
4      "id": 1,
5      "name": "Lunar Rover Wheels",
6      "createdAt": 1636742972000,
7      "updatedAt": 1636742972000,
8      "description": "Designed for traversing the rugged terrain of the moon, these wheels provide unrivaled traction and durability. Made from a lightweight composite, they ensure your rover is agile in challenging conditions.",
9      "slug": "lunar-rover-wheels",
10      "tags": [
11        {
12          "tagId": "space",
13          "name": "Space"
14        },
15        {
16          "tagId": "engineering",
17          "name": "Engineering"
18        },
19        {
20          "tagId": "rover",
21          "name": "Rover"
22        }
23      ],
24      "category": "Engineering Components",
25      "availability": "AVAILABLE"
26    },
27    {
28      "id": 2,
29      "name": "Zero-Gravity Moon Boots",
30      "createdAt": 1636742972000,
31      "updatedAt": 1636742972000,
32      "description": "Experience weightlessness with our Zero-Gravity Moon Boots! Specifically designed to provide comfort and support for lunar explorers, these boots are perfect for hopping around on the moon's surface.",
33      "slug": "zero-gravity-moon-boots",
34      "tags": [
35        {
36          "tagId": "space",
37          "name": "Space"
38        },
39        {
40          "tagId": "apparel",
41          "name": "Apparel"
42        },
43        {
44          "tagId": "moon",
45          "name": "Moon"
46        }
47      ],
48      "category": "Apparel",
49      "availability": "AVAILABLE"
50    },
51    {
52      "id": 3,
53      "name": "Asteroid Blaster Tool",
54      "createdAt": 1636742972000,
55      "updatedAt": 1636742972000,
56      "description": "A must-have tool for all space engineers! This high-powered blaster is designed for asteroid excavation and resource gathering, featuring an adjustable power setting for all your blasting needs.",
57      "slug": "asteroid-blaster-tool",
58      "tags": [
59        {
60          "tagId": "engineering",
61          "name": "Engineering"
62        },
63        {
64          "tagId": "tools",
65          "name": "Tools"
66        },
67        {
68          "tagId": "space",
69          "name": "Space"
70        }
71      ],
72      "category": "Engineering Tools",
73      "availability": "AVAILABLE"
74    },
75    {
76      "id": 4,
77      "name": "Interstellar Communication Device",
78      "createdAt": 1636742972000,
79      "updatedAt": 1636742972000,
80      "description": "Stay connected across the galaxies! Our Interstellar Communication Device allows you to send messages to fellow space travelers with secure encryption and planetary signal enhancement.",
81      "slug": "interstellar-communication-device",
82      "tags": [
83        {
84          "tagId": "tech",
85          "name": "Tech"
86        },
87        {
88          "tagId": "space",
89          "name": "Space"
90        },
91        {
92          "tagId": "communication",
93          "name": "Communication"
94        }
95      ],
96      "category": "Communication Devices",
97      "availability": "AVAILABLE"
98    },
99    {
100      "id": 5,
101      "name": "Galactic Navigation System",
102      "createdAt": 1636742972000,
103      "updatedAt": 1636742972000,
104      "description": "Never get lost in space again! Our Galactic Navigation System provides real-time location tracking, route planning, and hazard warnings to ensure safe travels through the cosmos.",
105      "slug": "galactic-navigation-system",
106      "tags": [
107        {
108          "tagId": "tech",
109          "name": "Tech"
110        },
111        {
112          "tagId": "navigation",
113          "name": "Navigation"
114        },
115        {
116          "tagId": "space",
117          "name": "Space"
118        }
119      ],
120      "category": "Navigation Devices",
121      "availability": "AVAILABLE"
122    },
123    {
124      "id": 6,
125      "name": "Mars Terrain Analyzer",
126      "createdAt": 1636742972000,
127      "updatedAt": 1636742972000,
128      "description": "A state-of-the-art device crafted for analyzing the soil and terrain of Mars. It provides scientists with crucial data about soil composition, moisture levels, and potential resources for future colonization.",
129      "slug": "mars-terrain-analyzer",
130      "tags": [
131        {
132          "tagId": "science",
133          "name": "Science"
134        },
135        {
136          "tagId": "analysis",
137          "name": "Analysis"
138        },
139        {
140          "tagId": "mars",
141          "name": "Mars"
142        }
143      ],
144      "category": "Scientific Devices",
145      "availability": "AVAILABLE"
146    },
147    {
148      "id": 7,
149      "name": "Comet Dust Collector",
150      "createdAt": 1636742972000,
151      "updatedAt": 1636742972000,
152      "description": "Gather dust from comets with this innovative collector! Designed for deep-space research, it captures samples with high efficiency while ensuring the integrity of the materials.",
153      "slug": "comet-dust-collector",
154      "tags": [
155        {
156          "tagId": "science",
157          "name": "Science"
158        },
159        {
160          "tagId": "research",
161          "name": "Research"
162        },
163        {
164          "tagId": "space",
165          "name": "Space"
166        }
167      ],
168      "category": "Research Equipment",
169      "availability": "AVAILABLE"
170    },
171    {
172      "id": 8,
173      "name": "Planetary Habitat Module",
174      "createdAt": 1636742972000,
175      "updatedAt": 1636742972000,
176      "description": "An essential for any space colonization mission! This habitat module provides a reliable, comfortable living environment for astronauts on planetary missions, complete with life support systems and smart technology.",
177      "slug": "planetary-habitat-module",
178      "tags": [
179        {
180          "tagId": "construction",
181          "name": "Construction"
182        },
183        {
184          "tagId": "space",
185          "name": "Space"
186        },
187        {
188          "tagId": "habitat",
189          "name": "Habitat"
190        }
191      ],
192      "category": "Living Spaces",
193      "availability": "AVAILABLE"
194    },
195    {
196      "id": 9,
197      "name": "Satellite Launch Pad Kit",
198      "createdAt": 1636742972000,
199      "updatedAt": 1636742972000,
200      "description": "Get your small satellites off the ground with our Satellite Launch Pad Kit! This kit includes everything you need to successfully launch mini satellites into orbit, including launch software and tracking system.",
201      "slug": "satellite-launch-pad-kit",
202      "tags": [
203        {
204          "tagId": "space",
205          "name": "Space"
206        },
207        {
208          "tagId": "launch",
209          "name": "Launch"
210        },
211        {
212          "tagId": "kit",
213          "name": "Kit"
214        }
215      ],
216      "category": "Launch Equipment",
217      "availability": "AVAILABLE"
218    },
219    {
220      "id": 10,
221      "name": "Planetary Resource Extractor",
222      "createdAt": 1636742972000,
223      "updatedAt": 1636842972000,
224      "description": "Tap into the resources of asteroids and moons! The Planetary Resource Extractor is engineered for durability and efficiency to help miners gather valuable materials from celestial bodies.",
225      "slug": "planetary-resource-extractor",
226      "tags": [
227        {
228          "tagId": "engineering",
229          "name": "Engineering"
230        },
231        {
232          "tagId": "mining",
233          "name": "Mining"
234        },
235        {
236          "tagId": "space",
237          "name": "Space"
238        }
239      ],
240      "category": "Mining Equipment",
241      "availability": "AVAILABLE"
242    }
243  ],
244  "summary": {
245    "total": 30
246  }
247}

Notice that the /products endpoint returns many more fields than id, name, and description. With Connectors (and for the sake of simplicity in this guide), you can select and return only the ones you need via selection mapping.

Selection mapping

In selection mapping, $ refers to the root of the response body. Since the list of products is nested under a products key, the first part of the selection is $.products. The product fields to map are wrapped within the $.products {}object. Since the Product type fields declared in the GraphQL schema map cleanly to product fields in the JSON response, the selection uses shorthand for field names.

These two selection mappings are equivalent:

GraphQL
selection: """
$.products {  
  id
  name
  description
}
GraphQL
selection: """
$.products {  
  id: id
  name: name
  description: description
}
What if schema field names are different from the JSON response?
You can use selection mapping to rename fields in your API. For example, if your REST API returns a name field that you want to rename title in your GraphQL API, you can map it like so:
GraphQL
selection: """
$.products {  
  id,
  title: name
  description
}

Notice you can still use shorthand for any other field names that don't need to change.
note
You can use selection mapping to transform values beyond just renaming fields.

Let's test things out by running a request in the Apollo Sandbox.

Run a request

Running rover dev starts a local GraphQL server at http://localhost:4000. This is an instance of Apollo Sandbox. You can write operations and make a request to your GraphQL API in Apollo Sandbox, then use its tools to validate the response and debug issues.

  1. In a browser, go to http://localhost:4000.

  2. In the central Operation panel, copy and paste the following query to get all products.

    GraphQL
    Example query
    query Products {
      products {
        id
        name
        description
      }
    }
  3. Run the request by clicking the ▶️ Products button. Check the response.

    You should see the products data you selected from the /products endpoint.

    Viewing requests in the Connectors Debuggers in Apollo Sandbox

That's it—a fully functional GraphQL API built on Connectors! You'll create a second Connector from scratch. Before that, this guide offers a slight detour to showcase the Sandbox's Connectors Debugger. If you're eager to write your own Connector, skip to the next section and return here when you need it.

Explore Connectors debugger

Explore the Connectors debugger

Suppose the example Connector hadn't worked out of the box—for example, that the selection mapping was incorrect. You can use the Connectors Debugger in the Sandbox to figure out what's gone wrong.
  1. Update your products.graphql so that the selection mapping is incorrect in the following way:
    GraphQL
    products.graphql
    type Query {
      products: [Product]
        # A @connect directive defines the API data source of a GraphQL schema field.
        @connect(
          source: "ecomm"
          http: { GET: "/products" }
          selection: """
          id
          name
          description
          """
        )
    }
    Why is this incorrect?
    This selection mapping doesn't wrap the field names in $.products{ } and therefore doesn't match the JSON response from /products. It would match if that endpoint returned a top-level list of products that weren't nested under a products key.
  2. Save your products.graphql to hot reload the Sandbox.
  3. Rerun the Products query by clicking the ▶️ Products button. Check the response.
    GraphQL
    Example query
    query Products {
      products {
        id
        name
        description
      }
    }
    With the incorrect schema, the Response panel shows null for the data returned.Query products' info with Connector subgraphThe Response panel also has a Connectors Debugger that can help determine what's gone wrong.
  4. Open it by clicking Response and selecting Connectors Debugger from the dropdown.Opening the Connectors Debugger from Apollo Sandbox
  5. You can see three mapping errors occurred, even though the HTTP response status code was 200.Viewing requests in the Connectors Debuggers in Apollo Sandbox
  6. Clicking into the Mapping panel displays some helpful error messages: Property .description not found in object, etc.
  7. The Response body panel of the debugger shows the raw JSON response and where the schema went wrong. The /products endpoint doesn't just return a list, it returns a list of products nested under the products key.Viewing requests in the Connectors Debuggers in Apollo Sandbox
  8. Correct the selection mapping in products.graphql by reverting to the original schema, nesting the current selection inside of $.products{ }.
    GraphQL
    products.graphql
    type Query {
      products: [Product]
        # A @connect directive defines the API data source of a GraphQL schema field.
        @connect(
          source: "ecomm"
          http: { GET: "/products" }
          selection: """
          $.products {
            id
            name
            description
          }
          """
        )
    }
  9. Save your changes to the products.graphql file in your editor.
  10. Rerun your request by clicking the ▶️ Products button. The Connectors Debugger should now show no errors. Toggle the right panel to the Response to confirm the response is as expected.Viewing requests in the Connectors Debuggers in Apollo Sandbox

Create a Connector with arguments

Next, you'll create your own Connector to interact with the /products/:id endpoint. Adding this Connector to your schema lets clients request a single product by ID from the same GraphQL API that lists all products.

  1. Add a new product field to the root Query type that requires an argument called id and returns a Product.

    GraphQL
    products.graphql
    type Query {
      products: [Product]
        @connect(
          source: "ecomm"
          http: { GET: "/products" }
          selection: """
          $.products {
            id
            name
            description
          }
          """
        )
    
      product(id: ID!): Product
    }
    GraphQL argument syntax
    In a GraphQL schema, arguments are enclosed in parentheses that come after a field's name. Each argument consists of two parts: 1) the argument's name and 2) the type of data that will be passed as the argument's value. Learn more about GraphQL arguments.
  2. Next, use the @connect directive to connect Query.product to the /products/:id endpoint. You can use arguments as path and query parameters via the $args variable.

    GraphQL
    products.graphql
    type Query {
      products: [Product]
        @connect(# -- snip -- #)
    
      product(id: ID!): Product
        @connect(
          source: "ecomm"
          http: { GET: "/products/{$args.id}" }
        )
    }
  3. Inspect the response body for this type of request to your REST API, for example, /products/1.

    /products/1
    JSON
    {
      "id": 1,
      "name": "Lunar Rover Wheels",
      "createdAt": 1675200000000,
      "updatedAt": 1675200000000,
      "description": "Innovatively designed wheels for lunar rovers, built to endure harsh moon terrain and provide optimal agility. Each wheel is constructed using advanced materials to withstand temperature fluctuations and dust.",
      "slug": "lunar-rover-wheels",
      "tags": [
        {
          "tagId": "1",
          "name": "Instruments"
        },
        {
          "tagId": "2",
          "name": "Space"
        }
      ],
      "category": "Engineering Components",
      "availability": "AVAILABLE",
      "variants": [
        {
          "name": "Standard Wheel",
          "price": {
            "original": 4999,
            "discounts": [],
            "final": 4999
          },
          "specifications": {
            "Material": {
              "value": "Titanium alloy"
            },
            "Diameter": {
              "value": "50 cm"
            }
          },
          "inventory": {
            "quantity": 100,
            "sellUnavailable": false
          },
          "shipping": {
            "ship1": {
              "weight": 5,
              "method": "GROUND",
              "estimate": {
                "price": 499,
                "arrival": 1675804800000
              }
            },
            "ship2": {
              "weight": 5,
              "method": "AIR",
              "estimate": {
                "price": 999,
                "arrival": 1675790400000
              }
            }
          },
          "upc": "0001234567890",
          "sku": "RW-001",
          "taxable": true,
          "variantId": "variant1"
        }
      ]
    }
  4. Based on the response shape, complete the selection mapping. Since the response is a single object, you can directly map its fields to Product type fields without $. See the mapping overview to learn more about how to use the mapping language.

    GraphQL
    products.graphql
    type Query {
      products: [Product]
        @connect(# -- snip -- #)
    
      product(id: ID!): Product
        @connect(
          source: "ecomm"
          http: { GET: "/products/{$args.id}" }
          selection: """
          id
          name
          description
          """
        )
    }
  5. Save your products.graphql.

That's it—you've created a Connector from scratch!

Run a request

Run the following query in your Sandbox to get a single product by id:

GraphQL
Sandbox request
query Product {
  product(id: "1") {
    id
    name
    description
  }
}

You should see results for just a single product with id 1. You can update the id to view results for other products. The next Connector showcases how you can orchestrate multiple REST API calls with just one GraphQL request.

Orchestrate calls with Connectors

The ecommerce demo API has a /products/:id/reviews endpoint to retrieve a particular product's reviews. Check out /products/1/reviews for an example.

/products/1/reviews
JSON
{
  "reviews": [
    {
      "id": 1,
      "rating": 5,
      "comment": "These wheels are perfect for my lunar exploration project!",
      "author": "John D",
      "createdAt": 1675200000000
    },
    {
      "id": 2,
      "rating": 4,
      "comment": "Solid build quality, just wish they were a little lighter.",
      "author": "Emma H",
      "createdAt": 1675200000000
    },
    /// ...
  ],
  "summary": {
    "total": 10,
    "averageRating": 4
  }
}

This endpoint returns a list of reviews under the reviews key, each with its own ID, numerical rating, comment, author, and createdAt timestamp. To display a product detail page with reviews, clients normally have to first query the /products/:id endpoint for product details and then the /products/:id/reviews for the product's reviews.

With Connectors, the client can make one request, asking for all the information at once. Behind the scenes, the graph is orchestrating the calls and combining the information into one client-friendly response. To define what the client response should look like, you need to update the GraphQL schema:

  1. Add a new Review type underneath the Product type in your products.graphql schema.

    GraphQL
    products.graphql
    extend schema
    # -- snip -- #
    
    type Product {
      id: ID!
      name: String
      description: String
    }
    
    type Review {
      id: ID!
      rating: Float
      comment: String
    }
  2. Since one product has many reviews, you define that relationship by adding a reviews field to the Product type. It returns a list of Review objects.

    GraphQL
    products.graphql
    extend schema
    # -- snip -- #
    
    type Product {
      id: ID!
      name: String
      description: String
      reviews: [Review]
    }
    
    type Review {
      id: ID!
      rating: Float!
      comment: String
    }
  3. To retrieve a product's reviews, add a Connector to the reviews field in the Product type.

    GraphQL
    products.graphql
    extend schema
    # -- snip -- #
    
    type Product {
      id: ID!
      name: String
      description: String
      reviews: [Review]
        @connect(
          source: "ecomm"
          http: { GET: "/products/{$this.id}/reviews" }
          selection: """
          $.reviews {
            id
            rating
            comment
          }
          """
        )
    }

    What's $this? Similar to the $args variable you used to access arguments for the /products/{$args.id} path when creating a Connector for Query.product, you can use $this to access an object's fields when creating a Connector for a field on a root type like Product.

That's it! Save your updated schema to see orchestration in action.

Run a request

Run a new query in your Sandbox to get a product's details and reviews:

GraphQL
Sandbox request
query ProductWithRating {
  product(id: "1") {
    id
    name
    description
    reviews {
      id
      rating
      comment
    }
  }
}

You should see results for a single product, including its reviews. The Sandbox offers additional views in the right panel to help you understand what's happening behind the scenes.

Inspect a query plan

Click Response and select Query Plan to inspect a visual representation of the steps taken to resolve a request.

Viewing a query plan in Apollo Sandbox

A query plan is created by the query planner, the part of the GraphOS Router that efficiently breaks down a GraphQL request into multiple, coordinated calls to various endpoints and services. Despite its name, the query planner handles all types of GraphQL operations—not just queries.

Because the request requires two calls to two separate endpoints, the query planner automatically sequences API calls (the two Fetch nodes) and then combines the results (the Flatten node).

The next Connector builds on the orchestration example by combining data from two endpoints about the same object type.

Enrich entities with Connectors

If you compare the product data returned by /products and /products/1, you'll notice that /products/:id returns many more fields than /products.

Show me the data
JSON
/products/
 {
      "id": 1,
      "name": "Lunar Rover Wheels",
      "createdAt": 1636742972000,
      "updatedAt": 1636742972000,
      "description": "Designed for traversing the rugged terrain of the moon, these wheels provide unrivaled traction and durability. Made from a lightweight composite, they ensure your rover is agile in challenging conditions.",
      "slug": "lunar-rover-wheels",
      "tags": [
        {
          "tagId": "space",
          "name": "Space"
        },
        {
          "tagId": "engineering",
          "name": "Engineering"
        },
        {
          "tagId": "rover",
          "name": "Rover"
        }
      ],
      "category": "Engineering Components",
      "availability": "AVAILABLE"
    },
JSON
/products/1
{
  "id": 1,
  "name": "Lunar Rover Wheels",
  "createdAt": 1675200000000,
  "updatedAt": 1675200000000,
  "description": "Innovatively designed wheels for lunar rovers, built to endure harsh moon terrain and provide optimal agility. Each wheel is constructed using advanced materials to withstand temperature fluctuations and dust.",
  "slug": "lunar-rover-wheels",
  "tags": [
    {
      "tagId": "1",
      "name": "Instruments"
    },
    {
      "tagId": "2",
      "name": "Space"
    }
  ],
  "category": "Engineering Components",
  "availability": "AVAILABLE",
  "variants": [
    {
      "variantId": "variant1",
      "name": "Standard Wheel",
      "price": {
        "original": 4999,
        "discounts": [],
        "final": 4999
      },
      "specifications": {
        "Material": {
          "value": "Titanium alloy"
        },
        "Diameter": {
          "value": "50 cm"
        }
      },
      "inventory": {
        "quantity": 100,
        "sellUnavailable": false
      },
      "shipping": {
        "ship1": {
          "weight": 5,
          "method": "GROUND",
          "estimate": {
            "price": 499,
            "arrival": 1675804800000
          }
        },
        "ship2": {
          "weight": 5,
          "method": "AIR",
          "estimate": {
            "price": 999,
            "arrival": 1675790400000
          }
        }
      },
      "upc": "0001234567890",
      "sku": "RW-001",
      "taxable": true
    }
  ]
}

This is a common pattern in REST APIs. Product listing pages let users browse multiple products at once, while product detail pages provide more comprehensive information about individual products.

Suppose your team wants to redesign the listing page to show swatches for different product variants, but that information is only available from the product detail endpoint. You can use Connectors to still make one request for the product listing page without having to change the underlying APIs. Specifically Connectors can coordinate the following tasks:

  • Calling the product listing endpoint (/products) to retrieve all products

  • Calling the product detail endpoints (/products/:id) to retrieve variant information for all products

  • Combining the data together into one response to the client

Apollo Federation uses entity types to represent a single object type that combines information from multiple data sources.

Working with entities

An entity is any object with data fields that can be fetched with one or more unique key fields, much like objects or rows in a database. To define an entity type in a GraphQL schema, you use the @key directive, followed by the unique identifier field(s). An entity type must also specify how to retrieve the data for its fields. You can use Connectors to accomplish this.

  1. Update your schema so that the Product type uses the @key directive. The product's id field works well as its unique identifier.

    GraphQL
    products.graphql
    extend schema
    # -- snip -- #
    
    type Product @key(fields: "id") {
      id: ID!
      # -- all the other fields -- #
    }
  2. To the same Product type, add the variants field that's only available from the product detail endpoint. Then add the corresponding Variant type.

    GraphQL
    products.graphql
    extend schema
    # -- snip -- #
    
    type Product @key(fields: "id") {
      id: ID!
      # -- all the other fields -- #
      variants: [Variant]
    }
    
    type Variant {
      id: ID!
      name: String
    }
  3. Add the variants field to your selection mapping for the Query.product Connector.

    GraphQL
    products.graphql
    type Query {
      products: [Product]
        @connect(# -- snip -- #)
    
      product(id: ID!): Product
      @connect(
        source: "ecomm"
        http: { GET: "/products/{$args.id}" }
        selection: """
        id
        name
        description
        variants {
          id: variantId
          name
        }
        """
      )
    }
    note
    Since /products/:id returns variant IDs nested as variant.variantId, we need to rename the field to match the GraphQL schema.
  4. Finally, add entity:true to the Query.product Connector.

    GraphQL
    products.graphql
    type Query {
      products: [Product]
        @connect(# -- snip -- #)
    
      product(id: ID!): Product
      @connect(
        source: "ecomm"
        http: { GET: "/products/{$args.id}" }
        selection: """
        id
        name
        description
        variants {
          id: variantId
          name
        }
        """
        entity: true
      )
    }

The entity:true part indicates that the Connector can use the unique key (the id from the /products endpoint) to merge the correct information together. All together, these additions provide the necessary instructions for how to retrieve any product fields you want, whether you're writing a query for one product or all products.

Run a request

Run a new query in your Sandbox to get information for all products, including each product's variants:

GraphQL
Sandbox request
query ProductsWithVariants {
  products {
    id
    name
    description
    variants {
      id
      name
    }
  }
}

In the right panel, you can see all product fields returned, including the variants information, into a single response.

Schema Visualization in GraphOS Studio

By checking out the Query Plan, you can see how Connectors are fetching data from two different endpoints and merging their data intelligently into the response.

Schema Visualization in GraphOS Studio

Connectors summary

Before moving on to some additional capabilities of Rover and GraphOS, let's summarize the Connectors you've developed:

  1. The existing example Connector fetches fields from the high-level /products endpoint.

  2. The argument Connector fetches fields from the /products/:id endpoint.

  3. The first orchestration Connector adds review data to products from the /products/:id/reviews endpoint.

  4. The entities Connector combines data from /products and /products/:id endpoints for a more complete representation of the Product entity type.

Any combination of data from all these endpoints is available to all your clients with a single API request to the GraphQL API you've been developing locally. Next, you'll learn how to publish your updated schema to the graph registry in GraphOS to share your graph with your team.

Next steps

To share and collaborate on your updated graph with your team, you need to publish it to GraphOS. Learn how, and see what else GraphOS has to offer in next guide.

Feedback

Forums