Join us for GraphQL Summit, October 10-12 in San Diego. Use promo code ODYSSEY for $400 off your pass.
Docs
Launch GraphOS Studio
You're viewing documentation for a previous version of this software. Switch to the latest stable version.

Using fragments


In GraphQL, fragments define pieces of data you may want to reuse in multiple places:

query HeroAndFriends($episode: Episode) {
hero(episode: $episode) {
name
...HeroDetails
friends {
...HeroDetails
}
}
}
fragment HeroDetails on Character {
name
appearsIn
}

Apollo iOS generates separate result types for s, which means they are a great way of keeping UI components or utility functions independent of specific queries.

One common pattern is to define a for a child view (like a UITableViewCell), and include the in a query defined at a parent level (like a UITableViewController). This way, the child view can easily be reused and only depends on the specific data it needs:

func configure(with heroDetails: HeroDetails?) {
textLabel?.text = heroDetails?.name
}

This also works the other way around. The parent view controller only has to know the name, but doesn't need to know anything about the s it specifies. You can make changes to the fragment definition without affecting the parent.

In fact, this is the main reason s included through s are not exposed directly, but require you to access the data through the fragment explicitly:

apollo.fetch(query: HeroAndFriendsQuery(episode: .empire)) { result in
guard let data = try? result.get().data else { return }
print(data.hero?.name) // Luke Skywalker
print(data.hero?.appearsIn) // WON'T WORK
print(data.hero?.fragments.heroDetails.appearsIn) // [.newhope, .empire, .jedi]
print(data.hero?.friends?.flatMap { $0?.fragments.heroDetails.name }.joined(separator: ", ")) // Han Solo, Leia Organa, C-3PO, R2-D2
}

In most cases, you'll simply pass the whole to a child view without needing to know anything about the data it specifies:

cell.configure(with: hero?.fragments.heroDetails)

Type conditions

The GraphQL type system includes interfaces and unions as abstract types that s can conform to. In the Star Wars example for example, both Humans and Droids implement the Character interface. If we query for a hero, the result can be either a human or a droid, and if we want to access any type-specific properties we will have to use a with a type condition:

query HeroAndFriends($episode: Episode) {
hero(episode: $episode) {
name
...DroidDetails
}
}
fragment DroidDetails on Droid {
name
primaryFunction
}

You can access named s with type conditions the same way you access other fragments, but their type will be optional to reflect the fact that their s will only be available if the matches:

apollo.fetch(query: HeroAndFriendsQuery(episode: .empire)) { result in
guard let data = try? result.get().data else { return }
data.hero?.fragments.droidDetails?.primaryFunction
}

Alternatively, you can use inline fragments with type conditions to query for type-specific s:

query HeroAndFriends($episode: Episode) {
hero(episode: $episode) {
name
... on Droid {
primaryFunction
}
}
}

And results from inline s with type conditions will be made available through specially generated as<Type> properties:

apollo.fetch(query: HeroAndFriendsQuery(episode: .empire)) { result in
guard let data = try? result.get().data else { return }
data.hero?.asDroid?.primaryFunction
}

You can also use inline s inside named fragments:

query HeroAndFriends($episode: Episode) {
hero(episode: $episode) {
name
...HeroDetails
friends {
...HeroDetails
}
}
}
fragment HeroDetails on Character {
name
... on Droid {
primaryFunction
}
}
apollo.fetch(query: HeroAndFriendsQuery(episode: .empire)) { result in
guard let data = try? result.get().data else { return }
data.hero?.fragments.heroDetails.asDroid?.primaryFunction
}

Apollo iOS automatically augments your queries to add a __typename to selection sets. This is used primarily to support conditional s, but it means a __typename property is always defined and can be used to differentiate between s manually if needed.

Previous
Performing mutations
Next
Client-side caching
Edit on GitHubEditForumsDiscord