Overview
Let's give our supergraph something to sing about—literally! We're going to pair our soundtracks data with meals that need some music! 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 recipes
Everyone needs a good soundtrack to go with the special dish they're whipping up! To that end, we're about to get to know the recipes API; it's another full-fledged GraphQL server with a schema, resolvers, and data sources.
We can use Sandbox to explore it. Here's the endpoint:
https://poetic-recipes-api-2f18189a9776.herokuapp.com
Right now, the API is simply a small collection of recipes. We can ask for things like:
- a random recipe
- the full list of recipes in its database
- the most recently added recipes
- a particular recipe's ingredients, cooking time, instructions, and more
The coolest part? It's not a .NET server. Instead, it's written in JavaScript and uses Apollo Server! Remember, this isn't a problem for our supergraph. Each subgraph we bring on board can be written using a different language or framework. We're about to see this in action!
Let's welcome this subgraph and its brand new functionality into our GraphQL API—we can do this without cloning the repository or making any adjustments at all.
Adding a subgraph
Head over to your supergraph's page in Studio and navigate to the Subgraphs page. We can see that our
soundtracks
subgraph is already here, pointing to where we hosted it.Click Add a subgraph.
https://studio.apollographql.com/Note: You can also add a subgraph using the Rover CLI, like what we did for the
soundtracks
subgraph! To find the instructions, click the arrow next to Add subgraph and select Add subgraph using the Rover CLI.We'll need to provide two things about the subgraph: its URL and its name.
Routing URLhttps://poetic-recipes-api-2f18189a9776.herokuapp.com/Subgraph namerecipeshttps://studio.apollographql.com/Then, click Add subgraph. It takes a few moments for GraphOS to check that the subgraph successfully composes with all other existing subgraphs and produces a supergraph schema (all necessary steps for the launch process). And that's it!
https://studio.apollographql.com/
Our new supergraph schema
Let's check out the Changelog through the navigation menu.
We can see our graph has grown—with types and fields all about recipes! We've got Ingredient
, Recipe
, and several new fields added to our Query
type like allRecipes
and recentlyAddedRecipes
.
All of these new types and fields are presumably all coming from the recipes
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!
We've got four new fields available from our Query
entry point: allRecipes
, randomRecipe
, recentlyAddedRecipes
, and a specific recipe(id)
.
Our supergraph has officially grown!
Sending a query
With both soundtracks and recipes data under 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 recipe
field.
This will open up Explorer with the Documentation tab showing the field and what we can use to build our query.
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 recipe
we can see its description—Returns a specific recipe based on its ID—along with the fields for a Recipe
type. Let's add the name
, cookingTime
, description
and instructions
.
query Recipe($recipeId: ID!) {recipe(id: $recipeId) {namecookingTimedescriptioninstructions}}
Because this field returns data for a specific recipe, we need to give it an ID as an argument. Here's what we can paste into the Variables panel.
{"recipeId": "recgUKbxnQssl9fYc"}
That's data from the recipes
subgraph! Let's bring data from the soundtracks
subgraph into the mix! Why don't we pull in data for featured playlists?
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 featuredPlaylists
and the Query.featuredPlaylists
field should pop up.
We'll select that field and now we can access it directly in the Documentation panel. Saves us a couple clicks, and it'll be especially helpful as our supergraph continues to grow!
Let's add the featuredPlaylists
field and ask for the name
of each playlist as the subfield.
Lastly, we'll rename the operation to be more explicit. Give it the name GetRecipeAndPlaylists
.
Your query should now look like this:
query GetRecipeAndPlaylists($recipeId: ID!) {recipe(id: $recipeId) {namecookingTimedescriptioninstructions}featuredPlaylists {name}}
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 on the arrow beside Response and select "Query Plan Preview".
We can view this as a chart, or as text if we select the icon to "Show plan as text".
QueryPlan {Parallel {Fetch(service: "recipes") {{recipe(id: $recipeId) {namecookingTimedescriptioninstructions}}},Fetch(service: "soundtracks") {{featuredPlaylists {name}}},},}
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 that the recipe
field and its subfields are coming from the recipes subgraph, and the featuredPlaylists
field and its subfields are coming from the soundtracks
subgraph. Both of those smaller operations are run in parallel and resolved by its own subgraph, and the router takes care of bundling them up to return in one single response back to the client.
Adding a subgraph was pretty straightforward! But right now, you might be feeling that the data in both subgraphs feel separate and siloed. There's nothing directly connecting soundtracks to a particular recipe. We want to be cooking with the perfect playlists after all!
The new feature: a recipe's recommended playlists
We want to ask for details about a specific recipe: its description, instructions, and ingredients, plus recommended playlists to cook with! For each playlist, we want to see the list of tracks as well.
Take a few moments to examine the mockup above and practice a schema-first design approach. Here are some questions for you to think about:
- How would you design your GraphQL schema to satisfy the data needs of this page?
- What already exists in our GraphQL API? What can we add to it?
- What might the query look like for this page?
Schema-first design
Ready? Here's what pieces of data (types and fields in our schema) that the page needs:
And what each playlist needs:
The dream query
Finally, here's what the query for that page could look like:
query GetRecipeAndRecommendedSoundtracks {randomRecipe {idnamedescriptioningredients {text}instructionsrecommendedPlaylists {idnamedescriptiontracks {idnameexplicitdurationMs}}}}
Note: Curious what this term "dream query" comes from? Check out Yelp's blog post on the topic for more detail.
Ideally, we would work with the frontend client teams to decide on and validate this query. Here, we've made the decision that the page returns the details of a random recipe (through the randomRecipe
field), and that particular recipe will have a field called recommendedPlaylists
.
This new recommendedPlaylists
field for the Recipe
type should be the responsibility of the soundtracks
subgraph, which contains all things related to playlists and tracks!
So we'll need a way to connect the data between both subgraphs to make our dream query work (hint: it's called entities!).
But first, let's set up our local development environment to ensure that the changes we make to the soundtracks
subgraph not only work correctly but also play nicely with the recipes
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.