Odyssey

GraphOS: Basics
deprecated

Getting started with GraphOSProject setupWhat's in a supergraph?Creating a supergraph in GraphOSQueries and the ExplorerSharing your supergraphGraphOS metrics & client awarenessUsing @defer
8. Using @defer
3m

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") {
id
name
cookingTime
prepTime
readyTime
servings
instructions
ingredients {
text
}
}
recentlyAddedRecipes {
name
cookingTime
servings
}
}

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.

https://studio.apollographql.com

Explorer with defer options

Our query should now look like this:

query GetRecipePage {
recipe(id: "recOZrH0RhjSjATBp") {
id
name
cookingTime
prepTime
readyTime
servings
instructions
ingredients {
text
}
}
... @defer {
recentlyAddedRecipes {
name
cookingTime
servings
}
}
}

Let's run the query now.

We can see a new section called "Response Timeline".

https://studio.apollographql.com

Explorer with response timline after defer

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): Fruit
randomFruit: Fruit
}
type Mutation {
buyFruit(fruitId: ID): Fruit
}
type Fruit {
id: ID
cost: Float
isInSeason: Boolean
color: String
}
Which of the following fields (and its subfields) can be deferred?
Which of the following statements are true?

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! 👋

Previous

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.

              GraphQL

              An open-source query language and specification for APIs that enables clients to request specific data, promoting efficiency and flexibility in data retrieval.

              operations

              A single query, mutation, or subscription that clients send to a GraphQL server to request or manipulate data.

              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              directive

              A GraphQL annotation for a schema or operation that customizes request execution. Prefixed with @ and may include arguments. For example, the @lowerCase directive below can define logic to return the username field in lowercase:

              type User {
              username: String! @lowerCase
              }
              directive

              A GraphQL annotation for a schema or operation that customizes request execution. Prefixed with @ and may include arguments. For example, the @lowerCase directive below can define logic to return the username field in lowercase:

              type User {
              username: String! @lowerCase
              }
              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              query

              A request for specific data from a GraphQL server. Clients define the structure of the response, enabling precise and efficient data retrieval.

              operation

              A single query, mutation, or subscription that clients send to a GraphQL server to request or manipulate data.

              operation

              A single query, mutation, or subscription that clients send to a GraphQL server to request or manipulate data.

              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              directive

              A GraphQL annotation for a schema or operation that customizes request execution. Prefixed with @ and may include arguments. For example, the @lowerCase directive below can define logic to return the username field in lowercase:

              type User {
              username: String! @lowerCase
              }
              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              query

              A request for specific data from a GraphQL server. Clients define the structure of the response, enabling precise and efficient data retrieval.

              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              Fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              entity type

              An object type in a federated graph that's defined as an entity.

              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              entity types

              An object type in a federated graph that's defined as an entity.

              directive

              A GraphQL annotation for a schema or operation that customizes request execution. Prefixed with @ and may include arguments. For example, the @lowerCase directive below can define logic to return the username field in lowercase:

              type User {
              username: String! @lowerCase
              }
              fragments

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              operation

              A single query, mutation, or subscription that clients send to a GraphQL server to request or manipulate data.

              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              fragment

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              query

              A request for specific data from a GraphQL server. Clients define the structure of the response, enabling precise and efficient data retrieval.

              query

              A request for specific data from a GraphQL server. Clients define the structure of the response, enabling precise and efficient data retrieval.

              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              deferred query

              A query with fields tagged with the @defer directive, indicating that the server can return other fields before the deferred fields are ready.

              Apollo Client

              An open-source library for client-side state management and GraphQL operation handling in Javascript/Typescript. Apollo Client is a fully featured caching GraphQL client with integrations for React, Angular, and more.

              directive

              A GraphQL annotation for a schema or operation that customizes request execution. Prefixed with @ and may include arguments. For example, the @lowerCase directive below can define logic to return the username field in lowercase:

              type User {
              username: String! @lowerCase
              }
              fields

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              fragment

              A selection set of fields that can be shared between multiple query operations. For example:

              fragment UserData on User {
              id: ID!
              firstName: String!
              lastName: String!
              }
              query GetUsers {
              allUsers {
              ...UserData
              }
              }
              query

              A request for specific data from a GraphQL server. Clients define the structure of the response, enabling precise and efficient data retrieval.

              GraphOS Router

              A scalable runtime for supergraphs that's fully integrated with GraphOS and based on the Apollo Router Core. Can be cloud- or self-hosted.

              directive

              A GraphQL annotation for a schema or operation that customizes request execution. Prefixed with @ and may include arguments. For example, the @lowerCase directive below can define logic to return the username field in lowercase:

              type User {
              username: String! @lowerCase
              }
              supergraph

              A unified, federated graph composed of separate GraphQL APIs using Apollo Federation. Enables a microservices architecture that exposes a unified GraphQL API to clients.

              supergraph

              A unified, federated graph composed of separate GraphQL APIs using Apollo Federation. Enables a microservices architecture that exposes a unified GraphQL API to clients.

              subgraphs

              A service in a federated GraphQL architecture. Acts as a module for a supergraph. Includes both GraphQL services and REST services integrated via Apollo Connectors.

              router

              The single access point for a federated GraphQL architecture. It receives incoming operations and intelligently routes them across component services before returning a unified response.

              GraphQL

              An open-source query language and specification for APIs that enables clients to request specific data, promoting efficiency and flexibility in data retrieval.

              GraphOS

              A platform for building and managing a supergraph. It provides a management plane to test and ship changes and runtime capabilities to secure and monitor the graph.

              variant

              Independent instances of a graph often used to represent different environments. Each variant has its own schema and own router.

              operation

              A single query, mutation, or subscription that clients send to a GraphQL server to request or manipulate data.

              field

              A unit of data that belongs to a type in a schema. Every GraphQL query requests one or more fields.

              type Author {
              # id, firstName, and lastName are all fields of the Author type
              id: Int!
              firstName: String
              lastName: String
              }
              metrics

              Measurements of the router's behavior that can be exported and monitored, for example, the number of in-flight requests.

              supergraph

              A unified, federated graph composed of separate GraphQL APIs using Apollo Federation. Enables a microservices architecture that exposes a unified GraphQL API to clients.

              NEW COURSE ALERT

              Introducing Apollo Connectors

              Connectors are the new and easy way to get started with GraphQL, using existing REST APIs.

              Say goodbye to GraphQL servers and resolvers—now, everything happens in the schema!

              Take the course