Overview
Let's combine our listings data with reviews from past guests. With GraphOS, it's straightforward: we're only a couple clicks away!
In this lesson, we will:
- Add a new subgraph to our supergraph using Studio
- Inspect an operation's query plan
Introducing reviews
We're about to get to know the reviews API; it's another full-fledged GraphQL server with a schema, data source, and datafetchers.
The reviews
service collects and serves up feedback from guests. We can query it for all the reviews in its database, or submit a new review.
Let's welcome this subgraph and brand new functionality into our GraphQL 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
subgraph.
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
subgraph runs locally on port 8080
, whereas the reviews
subgraph 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
subgraph has been reported—and our supergraph has grown!
Our new supergraph schema
Next, let's check out the Changelog through the navigation menu to see what new features and capabilities the reviews
subgraph has added to the API.
We can see our graph has grown—with types and fields all about reviews! We've got two new object types: Review
and SubmitReviewResponse
. We also have ReviewInput
as a new input type. And we've got two new root fields: Query.allReviews
and Mutation.submitReview
.
All of these new types and fields are presumably all coming from the reviews
subgraph. We can confirm which fields 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 supergraph. The Subgraph column indicates the subgraph each field is coming from!
Here we'll see that new field the reviews
subgraph contributed: allReviews
.
We can also review the new object types added to our schema under Objects.
Our supergraph 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 supergraph to the test? Let's try sending a query that involves both subgraphs.
Let's jump back to the Query tab in the Schema page, where we could see all our available entry points to the supergraph. Under the Actions column of the Schema page, click the Play icon right next to the allReviews
field.
This will open up Explorer with the Documentation tab showing the field and what we can use to build our query.
Note: If you have an operation 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 fields available to query on each returned Review
type. Let's add them all: id
, text
, and rating
.
query GetAllReviews {allReviews {idtextrating}}
That's data from the reviews
subgraph! Now let's bring data from the listings
subgraph 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 field. Hit Command + K
or Ctrl + K
to access the spotlight search. Start typing listing
and the Query.listing
field should pop up.
Let's add the listing
field and ask for its title
.
Lastly, we'll rename the operation to be more explicit. Give it the name GetAllReviewsAndListing
.
Your query should now look like this:
query GetAllReviewsAndListing($listingId: ID!) {allReviews {idtextrating}listing(id: $listingId) {title}}
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 field is coming from by inspecting the query plan. The query plan is like a blueprint for an operation: the set of instructions that the router uses to send smaller operations to the subgraphs responsible for those particular fields.
Click the dropdown in the Response panel and select Query Plan.
We can view the query plan as a chart, or as text if we select the icon to "Show plan as text". We won't worry too much about the query plan syntax—the router knows what's going on! But this is useful when we start to involve more subgraphs and more complex queries that need optimization.
For this particular query, we can see the word "Parallel", indicating that the router 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
field and its subfields are coming from the reviews
subgraph (that's the Fetch(service: "reviews")
piece), and the listing
field and its subfield are coming from the listings
subgraph. Both of those smaller operations are run in parallel and resolved by their own subgraph, and the router takes care of bundling up the data to return in one single response back to the client.
Adding a subgraph 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 query 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.
Here's what the dream query looks like:
query GetListingAndReviews {listing(id: "listing-1") {titledescriptionnumOfBedsamenities {namecategory}overallRatingreviews {idtext}}}
Note: We're including the listing's id
inline with the query here for ease of reference as we go through the course. In reality, this id
argument would be extracted out into a variable.
Let's dive into our reviews
data to see how we might put this feature together, and make our dream query 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.
id | text | rating | listingId |
---|---|---|---|
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
field 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
subgraph doesn't have any idea what a "listing" is. And similarly, our listings
subgraph has no awareness of reviews
! Even though they're part of the same supergraph, each subgraph lives in its own world.
We'll need a way to connect the data between both subgraphs to make our dream query 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 supergraph 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.
Practice
Key takeaways
- To add a new subgraph, we can use the Studio UI or Rover CLI.
- We can view the router's query plan 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
You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.