Docs
Launch GraphOS Studio

Using the @defer directive in Apollo Kotlin

Fetch slower schema fields asynchronously


⚠️ The @defer directive is currently

in Apollo Kotlin and enabled for use by default. If you have feedback on it, please let us know via
GitHub issues
or in the
Kotlin Slack community
.

Beginning with version 3.6.0, provides experimental support of

, which enables your queries to receive data for specific asynchronously. This is helpful whenever some fields in a take much longer to resolve than the others.

For example, let's say we're building a social media application that can quickly fetch a user's basic profile information, but retrieving that user's friends takes longer. If we include all of those in a single , we want to be able to display the profile information as soon as it's available, instead of waiting for the friend fields to resolve.

To achieve this, we can apply the @defer to an in-line that contains all slow-resolving related to friend data:

query PersonQuery($personId: ID!) {
person(id: $personId) {
# Basic fields (fast)
id
firstName
lastName
# Friend fields (slower)
... on User @defer {
friends {
id
}
}
}
}

In the generated code for this , the onUser for the will be nullable. That is because when the initial payload is received from the server, the fields of the fragment are not yet present. A Person will be emitted with only the basic filled in.

When the of the are available, a new Person will be emitted, this time with the onUser present and filled with the fields of the .

apolloClient.query(PersonQuery(personId)).toFlow().collect {
println("Received: $it")
if (it.dataAssertNoErrors.person.onUser == null) {
// Initial payload: basic info only
// ...
} else {
// Subsequent payload: with friends
// ...
}
}

Will print something like this:

Received: Person(id=1, firstName=John, lastName=Doe, onUser=null))
Received: Person(id=1, firstName=John, lastName=Doe, onUser=OnUser(friends=[Friend(id=2), Friend(id=3)]))

Limitations/known issues

  • @defer cannot be used with responseBased codegen.
  • Some servers might send an empty payload to signal the end of the stream. In such a case you will receive an extra terminal emission. You can filter it out by using distinct():
apolloClient.query(MyQuery()).toFlow()
.distinct() // filter out duplicates
.collect { /* ... */ }
Previous
Fragments
Next
Persisted queries
Edit on GitHubEditForumsDiscord

© 2024 Apollo Graph Inc.

Privacy Policy

Company