Overview
With GraphQL operations, some fields may take slower to resolve than others. From a user perspective, this could mean staring at a loading screen for longer than they want to.
The Apollo Router has a built-in feature up its sleeve to help us out with this issue! In this lesson, we will:
- Learn about the
@defer
directive - Apply the
@defer
directive to a slow field in our query
Investigating a slow query
Let's take this example of an operation regularly sent to the Poetic Plates API. The GetRecipePage
operation includes details about a specific recipe, its ingredients and instructions. It also asks for a list of recently added recipes.
query GetRecipePage {recipe(id: "recOZrH0RhjSjATBp") {idnamecookingTimeprepTimereadyTimeservingsinstructionsingredients {text}}recentlyAddedRecipes {namecookingTimeservings}}
When we try running this using Studio Explorer, we can see for ourselves just how long this query takes 🐢
From the client app, the important information is located in the recipe details. That's what the users want to see right away! Unfortunately, the recentlyAddedRecipes
field is slowing everything down. @defer
to the rescue!
The @defer
directive
The @defer
directive enables our queries to receive data for specific fields incrementally, instead of receiving all field data at the same time. This is helpful whenever some fields in a query take much longer to resolve than others, like the recentlyAddedRecipes
field and its subfields.
We can only defer certain fields in our schema, specifically:
- Root fields of the
Query
type (along with their subfields) - Fields of any entity type (along with their subfields)
Since recentlyAddedRecipes
is a root field in our Query
type, it matches the first situation and we can safely defer it!
Note: Curious about entity types? Check out our Odyssey Voyage series.
How to use @defer
To use the @defer
directive, we apply it to fragments in our queries.
So the GetRecipePage
operation with the recentlyAddedRecipes
field deferred would look like this:
query GetRecipePage {recipe(id: "recOZrH0RhjSjATBp") {idnamecookingTimeprepTimereadyTimeservingsinstructionsingredients {text}}... @defer {recentlyAddedRecipes {namecookingTimeservings}}}
There's an even easier way to do this in Explorer, so you don't have to remember the syntax every time.
With the operation open, we can place our cursor on the field we want to defer, right-click and select "Wrap with inline @defer fragment" (or "Extract @defer fragment") and Explorer automatically takes care of the syntax for us.
Let's run the query now.
We can see in the Response panel that a new section called "Response Timeline" has appeared at the bottom.
When we hover over the first circle, we can see the data about our recipe is returned, but not the recentlyAdded
Recipes field.
When we hover over the second circle, we can see the additional data for the recentlyAdded
Recipes field returned, a few milliseconds afterwards.
Amazing! This is going to make a big difference in our client app experiences.
Note: Clients must support receiving deferred query responses as multipart HTTP responses. This functionality is currently supported in Apollo Client for Web and Kotlin (experimental).
Practice
Use the schema below to answer the follow question:
type Query {availableFruits: [Fruit]fruit(id: ID): FruitrandomFruit: Fruit}type Mutation {buyFruit(fruitId: ID): Fruit}type Fruit {id: IDcost: FloatisInSeason: Booleancolor: String}
Key takeaways
- The
@defer
directive enables our queries to receive data for specific fields incrementally. We apply it to a fragment in our query. - Apollo Router comes with built-in support for the
@defer
directive.
Conclusion
And there we have it: Poetic Plates is a supergraph ready to receive queries and share the magic of poetic AI-generated recipes!
Awesome job! We've learned what the supergraph is and the components that make it work: subgraphs and a router. We created a supergraph with an existing GraphQL API and now it's set up for success inside GraphOS. We've got a public variant ready to receive queries for API consumers to try out. We've got access to operation and field metrics segmented by clients and we can use @defer
to improve our user experience.
This is only the beginning, we've still got a lot to learn about GraphOS and the supergraph. If you want to learn how to make changes to your supergraph safely and confidently, the next course, "GraphOS: Shipping your supergraph" is for you! See you there! 👋
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.