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.
The coolest part? It's not a Java server. Instead, it's written in JavaScript and uses Apollo Server! Remember, this isn't actually a problem for our supergraph: each subgraph we bring on board can be written using a different language or framework as necessary. We'll use our subgraph schema files, and datafetcher methods, to define how we'll pull data from both subgraphs—and match our meals to some music!
Right now, the recipes
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
Let's welcome this subgraph and 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.
Note: You can also add a subgraph using the Rover CLI. Click the arrow next to Add subgraph and select Add subgraph using the Rover CLI to find the instructions.
studio.apollographql.comWe'll need to provide two things about the subgraph: its URL and its name.
Routing URLhttps://poetic-recipes-api-2f18189a9776.herokuapp.com/Subgraph namerecipesstudio.apollographql.comThen, 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. And that's it!
studio.apollographql.com
Our new supergraph schema
Let's check out the Changelog through the navigation menu to see what new features and capabilities the recipes
subgraph has added to the API.
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
.
Let's dig deeper into the Objects available in the schema.
See that green "E" label on the Recipe
type? It stands for "entity"! You can hover over it for more information, but we'll get to it in a later lesson, so stay tuned.
Our supergraph has officially grown!
Sending a query
With both soundtrack and recipe data 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 recipe
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 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) {cookingTimedescriptioninstructions}}
Because this field returns data for a specific recipe, we need to give it an ID. 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.
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) {cookingTimedescriptioninstructions}featuredPlaylists {name}}
And under the Variables section:
{"recipeId": "recgUKbxnQssl9fYc"}
Before running the operation, let's click the dropdown in the Response panel and first inspect the Query Plan Preview.
This diagram shows how the router plans to execute the query that we've written in the Operation panel. We can see the word "Parallel", indicating that the router can make two separate requests simultaneously: one to recipes
and one to soundtracks
. These requests can run in parallel because neither soundtracks
nor recipes
depend upon the other's response to resolve their own data.
Cool—now let's actually 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". We can view this 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 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 you might be feeling that the data in both subgraphs is still separate and siloed. There's nothing directly connecting soundtracks to recipes or vice versa. We haven't yet achieved the experience that we want: with playlists being recommended to us based on the particular recipe we've selected.
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.
Here's what the dream query looks like:
query GetRecipeAndRecommendedSoundtracks {recipe(id: "rec3j49yFpY2uRNM1") {namedescriptioningredients {text}instructionsrecommendedPlaylists {idnamedescriptiontracks {explicitidnameuridurationMs}}}}
Note: We're including the recipe'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.
We can correlate soundtracks
data with a specific recipe by using at least one keyword—in our case, we'll use the recipe's name
field, and kick off a search with our soundtracks
subgraph to find recommendations that might match the vibe of what we're cooking!
There's only one problem: the soundtracks
subgraph doesn't have any idea what a recipe is, much less how to use its name
to even start a search. Even though it's part of the same supergraph, it lives in its own world! And right now, the Recipe
type and all of its fields live exclusively in the recipes
subgraph.
So 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 some changes to our soundtracks
service, so we'll first set up the right supergraph development environment. This will ensure that the changes we make to the soundtracks
subgraph not only work as we expect, but that they 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.