Overview
In some GraphQL operations, some fields may take longer to resolve than others. And this might mean our users staring at a loading screen for longer than we'd like.
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, we can experience for ourselves just how long this query takes. 🐢
From a client app's perspective, the important information is 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 waiting to receive 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. There's an easy way to do this in Explorer, so we don't have to remember the syntax every time.
With the GetRecipePage
operation open, we'll place our cursor on the field we want to defer: recentlyAddedRecipes
. Then, right-click and select "Wrap with inline @defer fragment" (or "Extract @defer fragment") and Explorer automatically takes care of the syntax for us.
Our query should now look like this:
query GetRecipePage {recipe(id: "recOZrH0RhjSjATBp") {idnamecookingTimeprepTimereadyTimeservingsinstructionsingredients {text}}... @defer {recentlyAddedRecipes {namecookingTimeservings}}}
Let's run the query now.
We can see a new section called "Response Timeline".
When we hover over the first circle, we can see the data about our recipe is returned, but not the recentlyAddedRecipes
field.
When we hover over the second circle, we can see the additional data returned, a few seconds afterwards.
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. - GraphOS Router comes with built-in support for the
@defer
directive.
Conclusion
And there we have it: we've got 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 using an existing GraphQL API and now it's set up for success inside GraphOS. We've got a public variant ready 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 had our appetizer, and I hope you're hungry for more!
If you want to learn how to make changes to your supergraph safely and confidently, the next course, "GraphOS: Safe API delivery" is for you! See you there! 👋
Share your questions and comments about this lesson
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.