What is `... on` doing in this GraphQL?
Asked Answered
S

2

17

I am trying to mimic what some GraphQL does, but I do not have access to be able to run the original. It is of the form:

query {
  dataSources(dataType: Ais) {
    ... on AisDataSource {
      messages(filter: {broadcastType: Static}) {
        ... on AisStaticBroadcast {
          field1
          field2

(I have ommitted the closing parentheses).

It is my understanding that ... on is either to include a fragment (none here), or to choose between alternatives (but these are nested). So is this query wrong, or is there more to ... on?

Suspense answered 30/4, 2020 at 15:15 Comment(0)
B
29

This

{
  user {
    ... on User {
      id
      username
    }
  }
}

and this

{
  user {
    ...UserFragment
  }
}

fragment UserFragment on User {
  id
  username
}

are equivalent. In both cases, you are using a fragment. In the first example, we simply refer to the fragment as an inline fragment.

When requesting a field that return a composite type (an object, interface or union), you must specify a selection set, or one or more fields for the return type. Since fragments must include a type condition (the on keyword plus the type name), they can be used to specify different selection sets depending on the type that's actually returned at runtime.

{
  user {
    ...RegularUserFragment
    ...AdminFragment
  }
}

fragment RegularUserFragment on RegularUser {
  id
  username
}

fragment AdminFragment on Admin {
  id
  username
  accessLevel
}

All we're saying is "if the type at runtime is this, then return this set of fields". If any of the fields inside the fragment also return a composite type, then those fields also have to specify a selection set for — that means additional fragments can be used inside those selection sets.

Butyrate answered 30/4, 2020 at 16:12 Comment(1)
Superb, many thanks! ! I must have missed that in the tutorial I read.Suspense
P
1

For those not yet clicked , here's an implementation using appolo graphql

Graphql schema:

  interface Animal {
    name: String
    age: String
    dob: String
    owner: String
    sound: String
  }

  type Dog implements Animal {
    name: String
    age: String
    dob: String
    owner: String
    sound: String
    color: String
  }

  type Cat implements Animal {
    name: String
    age: String
    dob: String
    owner: String
    sound: String
    weight: String
  }


Here Animal is an abstract type and the Dog and Cat has similar properties excpet color and weight which is different.

Resolver:

  Owner: {
    animal: (creator) => {
      return animals.find(anm => creator.name == anm.owner)
    }

  },

  Animal: {
    __resolveType(animal) {
      if (animal.sound == "Bark") {
        return 'Dog'
      } else {
        return 'Cat' 
      }
    }
  },

So a particular owner may have a cat or dog, so we have this scenario where if it's a dog output the color property and if it's a cat output weight. Consider it more like an if else statement.

An example query:

owner(id: $id) {
     animal {
        ... on Cat {
           weight
        }
        ... on Dog {
            color
          }
      }
}

Same query using fragments:

owner(id: $id) {
     animal {
         ...Catto
         ...Doggo
      }
}

fragment Catto on Cat {
  weight
}

fragment Doggo on Dog {
  color
}
Pasquale answered 22/7, 2024 at 17:58 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.