Get Started with Apollo Connectors and GraphOS
Connect and orchestrate REST APIs with a unified GraphQL API
Apollo Connectors are the quickest way to set up a GraphQL API backed by REST endpoints.
In this guide, you will:
Set up a GraphQL API
Connect live REST API endpoints to your GraphQL API using Apollo Connectors
Make requests in a sandbox environment to validate your GraphQL API is orchestrating REST API calls
Learn how to use Apollo's tools like GraphOS Studio, Rover CLI and Apollo Sandbox
Prefer to start with a high-level conceptual understanding? Check out the Apollo Connectors Overview. Otherwise, let's start building!
Step 1. Set up your GraphQL API
This step sets up a GraphQL API in a development environment using the following Apollo tools:
GraphOS Studio: This is the primary web interface for GraphOS. Studio helps you monitor, manage, and collaborate on your GraphQL APIs.
The Rover CLI: This is the primary command-line interface for GraphOS.
Apollo Sandbox: This local development tool lets you test requests, inspect responses, debug connectors, and more.
Create a GraphOS account
You need an account to work with GraphOS. Sign up for a Free plan at studio.apollographql.com.
Create a graph
A GraphQL API exposes a graph, a schema-defined network of interconnected data that enables clients to traverse relationships and fetch exactly what they need in a single request. To set up your GraphQL API, start by creating a new graph in GraphOS Studio.
If your organization doesn't have any graphs yet, click Connect a REST API.
If you already have existing graphs, click the down chevron (
⌄
) to the right of Create a new graph, then click Connect a REST API.Enter a graph title and graph ID and keep the defaults for the other form elements. Then click Create and continue.
Next, follow the instructions to set up your local development environment. You should end up with a
supergraph.yaml
andproducts.graphql
file in your local project.File overview- The
supergraph.yaml
specifies which Apollo Federation version to use and configures your subgraphs, the different services that make up your supergraph. - The
products.graphql
contains a GraphQL schema and defines your graph's structure, types, and capabilities. The schema is where you define connectors and where this guide spends most of its time.
Once
rover dev
is running, your terminal should look something like this:terminalsupergraph config loaded successfully warning: Do not run this command in production! It is intended for local development only. ==> Watching products.graphql for changes WARN: Connector debugging is enabled, this may expose sensitive information. ==> your supergraph is running! head to http://localhost:4000 to query your supergraph successfully composed with version 2.10.0
The last step in the modal brings you back to this quickstart guide.
- The
🎉 Congratulations—you've successfully started a local development session where you can explore, develop, and publish updates to your graph!
Step 2. Connect REST APIs
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? 🛠️
Explore example connector
Let's take a look at the products.graphql
GraphQL schema to see how connectors work.
The first few lines use
@link
directives to enable the latest versions of federation and connectors.GraphQLproducts.graphqlextend schema @link( url: "https://specs.apollo.dev/federation/v2.10" import: ["@key"] ) @link( url: "https://specs.apollo.dev/connect/v0.1" import: ["@connect", "@source"] )
In the next few lines, the
@source
directive creates a reusable configuration that each connector can reference. In this case, it only sets thebaseURL
to the ecommerce demo API this guide uses. You can also add request headers to a@source
.GraphQLproducts.graphql@source( name: "ecomm" http: { baseURL: "https://ecommerce.demo-api.apollo.dev/" } )
Product
is the standard object type the GraphQL API returns.GraphQLproducts.graphqltype Product { id: ID! name: String description: String }
The
Query
type has aproducts
field that the@connect
directive implements.What's the Query type?In a GraphQL schema, theQuery
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.GraphQLproducts.graphqltype 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
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:
selection: """
$.products {
id
name
description
}
selection: """
$.products {
id: id
name: name
description: description
}
What if schema field names are different from the JSON response?
name
field that you want to rename title
in your GraphQL API, you can map it like so:selection: """
$.products {
id,
title: name
description
}
Notice you can still use shorthand for any other field names that don't need to change.
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.
In a browser, go to http://localhost:4000.
In the central Operation panel, copy and paste the following query to get all products.
GraphQLExample queryquery Products { products { id name description } }
Run the request by clicking the ▶️ Products button. Check the response.
You should see the products data you selected from the
/products
endpoint.
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, can 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.- Update your
products.graphql
so that the selection mapping is incorrect in the following way:GraphQLproducts.graphqltype 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 aproducts
key. - Save your
products.graphql
to hot reload the Sandbox. - Rerun the
Products
query by clicking the ▶️ Products button. Check the response.With the incorrect schema, the Response panel showsGraphQLExample queryquery Products { products { id name description } }
null
for the data returned.The Response panel also has a Connectors Debugger that can help determine what's gone wrong.
- Open it by clicking Response and selecting Connectors Debugger from the dropdown.
- You can see three mapping errors occurred, even though the HTTP response status code was
200
. - Clicking into the Mapping panel displays some helpful error messages:
Property .description not found in object
, etc. - 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 theproducts
key. - Correct the selection mapping in
products.graphql
by reverting to the original schema, nesting the current selection inside of$.products{ }
.GraphQLproducts.graphqltype 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 } """ ) }
- Save your changes to the
products.graphql
file in your editor. - 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.
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.
Add a new
product
field to the rootQuery
type that requires an argument calledid
and returns aProduct
.GraphQLproducts.graphqltype Query { products: [Product] @connect( source: "ecomm" http: { GET: "/products" } selection: """ $.products { id name description } """ ) product(id: ID!): Product }
GraphQL argument syntaxIn 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.Next, use the
@connect
directive to connectQuery.product
to the/products/:id
endpoint. You can use arguments as path and query parameters via the$args
variable.GraphQLproducts.graphqltype Query { products: [Product] @connect(# -- snip -- #) product(id: ID!): Product @connect( source: "ecomm" http: { GET: "/products/{$args.id}" } ) }
Inspect the response body for this type of request to your REST API, for example,
/products/1
./products/1JSON{ "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" } ] }
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.GraphQLproducts.graphqltype Query { products: [Product] @connect(# -- snip -- #) product(id: ID!): Product @connect( source: "ecomm" http: { GET: "/products/{$args.id}" } selection: """ id name description """ ) }
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:
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
{
"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:
Add a new
Review
type underneath theProduct
type in yourproducts.graphql
schema.GraphQLproducts.graphqlextend schema # -- snip -- # type Product { id: ID! name: String description: String } type Review { id: ID! rating: Float comment: String }
Since one product has many reviews, you define that relationship by adding a
reviews
field to theProduct
type. It returns a list ofReview
objects.GraphQLproducts.graphqlextend schema # -- snip -- # type Product { id: ID! name: String description: String reviews: [Review] } type Review { id: ID! rating: Float! comment: String }
To retrieve a product's reviews, add a connector to the
reviews
field in theProduct
type.GraphQLproducts.graphqlextend 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 forQuery.product
, you can use$this
to access an object's fields when creating a connector for a field on a root type likeProduct
.
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:
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.
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
{
"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"
},
{
"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 productsCalling the product detail endpoints (
/products/:id
) to retrieve variant information for all productsCombining the data together into one response to the client
GraphQL 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.
Update your schema so that the
Product
type uses the@key
directive. The product'sid
field works well as its unique identifier.GraphQLproducts.graphqlextend schema # -- snip -- # type Product @key(fields: "id") { id: ID! # -- all the other fields -- # }
To the same
Product
type, add thevariants
field that's only available from the product detail endpoint. Then add the correspondingVariant
type.GraphQLproducts.graphqlextend schema # -- snip -- # type Product @key(fields: "id") { id: ID! # -- all the other fields -- # variants: [Variant] } type Variant { id: ID! name: String }
Add the
variants
field to your selection mapping for theQuery.product
connector.GraphQLproducts.graphqltype 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 } """ ) }
noteSince/products/:id
returns variant IDs nested asvariant.variantId
, we need to rename the field to match the GraphQL schema.Finally, add
entity:true
to theQuery.product
connector.GraphQLproducts.graphqltype 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
:
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.
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.
Connectors summary
Before moving on to some additional capabilities of Rover and GraphOS, let's summarize the connectors you've developed:
The existing example connector fetches fields from the high-level
/products
endpoint.The argument connector fetches fields from the
/products/:id
endpoint.The first orchestration connector adds review data to products from the
/products/:id/reviews
endpoint.The entities connector combines data from
/products
and/products/:id
endpoints for a more complete representation of theProduct
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.
Step 3. Publish your graph
Throughout this guide, you've updated products.graphql
to expand your graph's capabilities.
To share your updates with the rest of your GraphOS organization and to get your updated schema into GraphOS's schema management pipeline, you need to publish it to GraphOS.
You publish schemas using the rover subgraph publish
command:
Copy the following multi-line command. Replace
<APOLLO_KEY>
<GRAPH_REF>
with key the graph ref from the multi-linerover dev
command you ran at the beginning of the guide.terminalAPOLLO_KEY=<APOLLO_KEY> \ rover subgraph publish <GRAPH_REF> \ --schema ./products.graphql \ --name products \ --routing-url http://ignored
Paste and run your updated multi-line command. Once the command completes, you'll see the following in your terminal:
terminalA new subgraph called 'products' was created in <GRAPH_REF> The supergraph schema for <GRAPH_REF> was updated, composed from the updated 'products' subgraph Monitor your schema delivery progression on studio: <STUDIO_URL>
Nice! If you go to the <STUDIO_URL>
provided, you land on your graphs Launches page in GraphOS Studio. With this updated schema published, you can further explore your graph in Studio and share it with your team by inviting them to your organization.
For example, from the Schema tab, your team can view a Visualization of the types and relationships in your graph.
Once you start collecting metrics, you can use the visualization tool to create heatmaps to identify fields that are most frequently used, or have the highest latency or errors. You can also analyze detailed information about your operations usage and performance from the Insights tab:
Next steps
Depending on your goals, you have several options for learning more about Apollo Connectors and GraphOS' capabilities.
Connectors resources
Learn more about connectors by checking out the connectors documentation.
Want to see how others are using connectors? Check out the Apollo Connectors Community
POST
requests.GraphOS resources
To learn more about Studio features, including schema checks, linting, and schema proposals, check out the GraphOS platform documentation. If you'd like a visual tour of some of these features, check out the video below.