Fragments
Fragments are the primary unit of composition in Graphql. They...
- must specify the type they apply to
- cannot be specified on any input value (scalar, enumeration, or input object).
- can be specified on object types, interfaces, and unions.
Below, the part after on
is the type we are selecting from
- so
people
is of typePerson
, and we want thefirstName
andlastName
fields frompeople(id: "7")
fragment NameParts on Person {
firstName
lastName
}
query GetPerson {
people(id: "7") {
...NameParts
avatar(size: LARGE)
}
}
Conditional Fragments
Type Conditions
- allow us to conditionally include fields based on their runtime type.
On Facebook, imagine we have 2 different fields that both specify a count
: User Friends, and Page Likes. We have set up our schema in such a way that we define a Profile
type, which can be either a User
or Page
.
Now imagine that we want to write a query that gets back both the friends count of Kyle Tycholiz, and it gets back the like count of the Never Forget page. If we want to write this in a single query, we are presented with a problem: while both have a field count
, the parent field is different, namely friends
and likes
. To solve this problem, we must use fragments, which will be applied depending on the type of profile that is returned in the query.
When we query for this, the profiles
root field returns a list where each element could be a Page
or a User
.
{
profiles(name: ["kyletycholiz", "neverforget"]) {
name
...userFragment
...pageFragment
}
fragment userFragment on User {
friends {
count
}
}
fragment pageFragment on Page {
likers {
count
}
}
}
Inline Fragments
if querying a field that returns an interface or union type, we need to use inline fragments to access data on the underlying concrete type
- These can be used to compose fields in a type-dependent way
The above Facebook example can be accomplished using inline fragments.
The Graphql server will determine whether to return homeAddress
or address
at runtime, depending on whether the requested object is a User
or Business
query Foo {
profile(id: $id) {
url
... on User {
homeAddress
}
... on Business {
address
}
}
}
Practical usage
- Imagine we had an interface
Character
that represents a character from Star Wars:
interface Character {
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
}
- Imagine now we create two types that implement this interface:
type Human implements Character {
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
starships: [Starship]
totalCredits: Int
}
type Droid implements Character {
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
primaryFunction: String
}
- As we can see, Droid has the field
primaryFunction
, while Human does not- This means that if we were to make a query that wanted that field back, we would get an error:
query HeroForEpisode($ep: Episode!) {
hero(episode: $ep) {
name
primaryFunction
}
}
// PRODUCES ERROR: cannot query field 'primaryFunction' on type Character
- To get around this, we need to use an inline fragment:
query HeroForEpisode($ep: Episode!) {
hero(episode: $ep) {
name
... on Droid {
primaryFunction
}
}
}
Backlinks