Fragments


The GraphQL spec defines two types of fragments:

  • Named fragments, which enable you to reuse a set of fields across multiple operations or selection sets.

  • Inline fragments, which can group fields and apply type conditions or directives but are not reusable.

Both named and inline fragments can be used as type conditions, which enables you to access fields of polymorphic types.

Read the guide on type conditions to learn more.

Named fragments

A named fragment is defined in a .graphql file, just like an operation definition. A named fragment always has a name and a "parent type", that is, the type in the schema that it can be applied to. This fragment can be included in a selection set in an operation definition.

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

GraphQL
HeroDetailsFragment.graphql
1fragment HeroDetails on Character {
2  name
3  appearsIn
4}
GraphQL
HeroAndFriendsQuery.graphql
1query HeroAndFriends {
2  hero {
3    name
4    ...HeroDetails
5    friends {
6      ...HeroDetails
7    }
8  }
9}

Apollo iOS generates a type-safe model for the HeroDetails fragment that looks something like this (details are omitted to focus on the class structure):

Swift
HeroDetails.graphql.swift
1struct HeroDetails: MySchema.SelectionSet, Fragment {
2  let name: String
3  let appearsIn: [Episode]
4}

The result data models generated for the HeroAndFriendsQuery will include the fields from the HeroDetails fragment and are able to be converted into the HeroDetails fragment model.

Swift
HeroAndFriendsQuery.graphql.swift
1class HeroAndFriendsQuery: GraphQLQuery {
2  struct Data: SelectionSet {
3    let hero: Hero
4
5    struct Hero: SelectionSet {
6      let name: String
7      let friends: [Friend]
8      let appearsIn: [Episode]
9
10      // Fragment Conversion Declaration
11      var fragments: Fragments
12      struct Fragments {
13        var heroDetails: HeroDetails { ... }
14      }
15
16      struct Friend: SelectionSet {
17        let name: String
18        let appearsIn: [Episode]
19
20        // Fragment Conversion Declaration
21        var fragments: Fragments
22        struct Fragments {
23          var heroDetails: HeroDetails { ... }
24        }
25      }
26    }
27  }
28}

Fragment conversion

A result model that includes a fragment in it's definition will contain a Fragments struct that facilitates fragment conversion.

Both the Hero and the Friend models from the HeroAndFriendsQuery above have a Fragments struct and can be converted to the HeroDetails fragment.

Swift
1let hero: HeroDetails = data.hero.fragments.heroDetails
2let friends: [HeroDetails] = data.hero.friends.map { $0.fragments.heroDetails }

Fragment reuse

Fragment conversion allows you to reuse fragments as common models across different operations or multiple objects within the same operation.

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

The HeroDetails fragment above is used for both the Hero and Friend models from the HeroAndFriendsQuery, but a hero can be displayed alongside their friends in your application by showing a list of views that each are configured with a HeroDetails fragment model.

Swift
HeroDetailsView.swift
1struct HeroDetailsListView: View {
2  let data: HeroAndFriendsQuery.Data
3
4  var body: some View {
5    VStack {
6      HeroDetailsView(hero: data.hero.fragments.heroDetails)
7      for friend in data.hero.friends {
8        HeroDetailsView(hero: friend.fragments.heroDetails)
9      }
10    }
11  }
12}
13
14struct HeroDetailsView: View {
15  let hero: HeroDetails
16
17  var body: some View {
18    HStack {
19      Text(hero.name)
20      Text(hero.appearsIn.description)
21    }
22  }
23}

You can add additional data to the HeroDetails fragment and display that data in the HeroDetailsView without affecting the parent view at all. Additionally, the HeroDetailsView can be used with other GraphQL operations that include the HeroDetails fragment.

Inline fragments

An inline fragment is a fragment that has no name. It is declared "inline" within another definition and cannot be reused. Inline fragments can be included in an operation definition, a named fragment definition, or nested inside another inline fragment. They are typically used to conditionally include fields in an operation using a type conditions or the @skip/@include directives.

Apollo iOS does not generate individual models for inline fragments, instead they affect the generated models for the operations or fragments containing them.

You can use inline fragments with type conditions to query for type-specific fields:

GraphQL
1query HeroAndFriends($episode: Episode) {
2  hero(episode: $episode) {
3    name
4    ... on Droid {
5      primaryFunction
6    }
7  }
8}

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

Swift
1let name: String = data.hero.name
2let primaryFunction: String = data.hero.asDroid?.primaryFunction

For more information about how to use inline fragments as type conditions, see the type conditions documentation.

Feedback

Edit on GitHub

Forums