5. Adding a subgraph


Let's combine our listings data with reviews from past guests. With , it's straightforward: we're only a couple clicks away!

In this lesson, we will:

  • Add a new to our using Studio
  • Inspect an 's

Introducing reviews

We're about to get to know the reviews API; it's another full-fledged with a schema, , and datafetchers.

The reviews service collects and serves up feedback from guests. We can it for all the reviews in its database, or submit a new review.

Let's welcome this and brand new functionality into our API—we can do this by cloning the repository, and reporting its schema right away. No adjustments necessary!

Cloning reviews

In your terminal, navigate out of the listings directory so that you're in the main dgs-federation project folder. Then, run the following command to clone the reviews .

git clone https://github.com/apollographql-education/odyssey-federation-dgs-reviews.git reviews

Note: We've attached an additional reviews flag to the command above. This will clone the provided repository in a folder called reviews, for clarity purposes.

Here's our project structure now:

📦 dgs-federation
┣ 📂 listings
┣ 📂 reviews
┗ 📂 router

Let's open up reviews in a new IDE window and start it up. Locate the green play button if you're using IntelliJ, or run the following command in the repository terminal.

./gradlew bootRun

Adding a subgraph

Let's get our reviews schema published to the registry.

Copy the command below, swapping in your value for APOLLO_GRAPH_REF. Then, in a terminal opened to the reviews directory, paste and run it.

rover subgraph publish <APOLLO_GRAPH_REF> \
--name reviews \
--schema ./src/main/resources/schema/schema.graphqls \
--routing-url http://localhost:8090/graphql

Note: The listings runs locally on port 8080, whereas the reviews runs on 8090. Make sure when you publish the reviews schema, you reference the correct port number!

Now let's return to Studio, and navigate to the Subgraphs tab in the left-hand menu. We'll see that our new reviews has been reported—and our has grown!


A screenshot of the Subgraphs page, showing two subgraphs: listings and reviews

Our new supergraph schema

Next, let's check out the Changelog through the navigation menu to see what new features and capabilities the reviews has added to the API.


The Changelog page in Studio, showing additions to the schema from the reviews subgraph

We can see our has grown—with types and all about reviews! We've got two new : Review and SubmitReviewResponse. We also have ReviewInput as a new input type. And we've got two new root : Query.allReviews and Mutation.submitReview.

All of these new types and are presumably all coming from the reviews . We can confirm which are coming from which subgraph by heading over to the Schema page.

Under the Reference tab, with Query selected, we can see the entry points to our . The Subgraph column indicates the each is coming from!


The Schema page in Studio, showing fields on the Query type and which subgraph provides them

Here we'll see that new the reviews contributed: allReviews.

We can also review the new added to our schema under Objects.


The Schema page in Studio, showing the object types and which subgraph provides them

Our has officially grown!

Sending a query

Data for both reviews and listings are at our fingertips; are you itching to put the power of our to the test? Let's try sending a that involves both .

Let's jump back to the Query tab in the Schema page, where we could see all our available entry points to the . Under the Actions column of the Schema page, click the Play icon right next to the allReviews .


The play button beside the allReviews field outlined

This will open up Explorer with the Documentation tab showing the and what we can use to build our .


The Explorer with the Documentation tab opened to the listing field

Note: If you have an currently in the Operation panel, clear it or open up a new Explorer tab. We want to start fresh here!

Under allReviews we can see its description—"A list of all the reviews in the database"—along with the available to on each returned Review type. Let's add them all: id, text, and rating.

query GetAllReviews {
allReviews {

That's data from the reviews ! Now let's bring data from the listings into the mix: why don't we pull in data for a specific listing?

There's a handy shortcut in Explorer to search our schema for that . Hit Command + K or Ctrl + K to access the spotlight search. Start typing listing and the Query.listing should pop up.


The Explorer with the search modal pulled up, and Query.listing selected from the dropdown

Let's add the listing and ask for its title.

Lastly, we'll rename the to be more explicit. Give it the name GetAllReviewsAndListing.

Your should now look like this:

query GetAllReviewsAndListing($listingId: ID!) {
allReviews {
listing(id: $listingId) {

And under the Variables section:

"listingId": "listing-1"

Let's run it!

Woohoo, and we get data back! One query, but with data coming from two separate subgraphs 🤯🎉

The query plan

We can validate where exactly the data for each is coming from by inspecting the query plan. The is like a blueprint for an : the set of instructions that the uses to send smaller operations to the responsible for those particular .

Click the dropdown in the Response panel and select Query Plan.


The Response panel opened to the Query Plan, which shows how the router will execute the query to the subgraphs

We can view the as a chart, or as text if we select the icon to "Show plan as text". We won't worry too much about the syntax—the knows what's going on! But this is useful when we start to involve more and more complex queries that need optimization.


Query plan preview in text format, showing which subgraph each field is fetched from

For this particular , we can see the word "Parallel", indicating that the can make two separate requests simultaneously: one to reviews and one to listings. These requests can run in parallel because neither listings nor reviews depend upon the other's response to resolve their own data.

We can also see that the allReviews and its subfields are coming from the reviews (that's the Fetch(service: "reviews") piece), and the listing and its subfield are coming from the listings . Both of those smaller are run in parallel and resolved by their own subgraph, and the takes care of bundling up the data to return in one single response back to the client.

Adding a was pretty straightforward! But you might be feeling that the data in both subgraphs is still separate and siloed. There's nothing directly connecting listings to reviews or vice versa.

The new feature: a listing's rating & reviews

We want to be able to for details about a specific listing: its title, description, number of beds, and amenities, plus whatever reviews have been written for it! And let's go one step further—let's also include a listing's overallRating, calculated from all its ratings put together.

A preview of what our listing data should look like, supplemented with reviews and overall rating

Here's what the dream looks like:

query GetListingAndReviews {
listing(id: "listing-1") {
amenities {
reviews {

Note: We're including the listing's id inline with the here for ease of reference as we go through the course. In reality, this id would be extracted out into a .

Let's dive into our reviews data to see how we might put this feature together, and make our dream come true.

Data in reviews

When we booted up the reviews server, it automatically seeded its in-memory database with some sample reviews.

The reviews table defines four columns: id, text, rating, and listingId. Here's a table that illustrates this data put together.

1"Wow, what an experience! Ive never stayed in a cave before, so I was a little unprepared. Luckily, this listing had all the amenities I needed to feel safe and prepared for anything."4"listing-1"
2"100% enjoyed the wilderness experience. Do not book if you are not an adventurer and lover of the outdoors."5"listing-2"
3"Meh, could be better honestly. I was expecting more. The lake was the only good part."2"listing-3"

That listingId is exactly what we'll need to be able to correlate a particular review with the listing it was written about.

There's only one problem: aside from this column in our database, our reviews doesn't have any idea what a "listing" is. And similarly, our listings has no awareness of reviews! Even though they're part of the same , each lives in its own world.

We'll need a way to connect the data between both to make our dream work (hint: it's called entities!). This will involve a few changes to both of our subgraphs, so we'll first set up the right development environment. This will ensure that any changes we make to one subgraph not only work as we expect, but that they also play nicely with the other subgraph.


To add a new subgraph, which of these values does GraphOS need to know?

Key takeaways

  • To add a new , we can use the Studio UI or .
  • We can view the 's using Explorer.

Up next

Let's set ourselves up for local development in the next lesson.


Share your questions and comments about this lesson

This course is currently in

. Your feedback helps us improve! If you're stuck or confused, let us know and we'll help you out. All comments are public and must follow the Apollo Code of Conduct. Note that comments that have been resolved or addressed may be removed.

You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.