Field Selection Merging

Formal Specification

  • Let set be any selection set defined in the GraphQL document.
  • FieldsInSetCanMerge ( set ) must be true.

FieldsInSetCanMerge

(

set

)

  1. Let fieldsForName be the set of selections with a given response name in set including visiting fragments and inline fragments.
  2. Given each pair of members fieldA and fieldB in fieldsForName :
    1. SameResponseShape ( fieldA , fieldB ) must be true.
    2. If the parent types of fieldA and fieldB are equal or if either is not an Object Type:
      1. fieldA and fieldB must have identical field names.
      2. fieldA and fieldB must have identical sets of arguments.
      3. Let mergedSet be the result of adding the selection set of fieldA and the selection set of fieldB .
      4. FieldsInSetCanMerge ( mergedSet ) must be true.

SameResponseShape

(

fieldA

,

fieldB

)

  1. Let typeA be the return type of fieldA .
  2. Let typeB be the return type of fieldB .
  3. If typeA or typeB is Non‐Null.
    1. typeA and typeB must both be Non‐Null.
    2. Let typeA be the nullable type of typeA
    3. Let typeB be the nullable type of typeB
  4. If typeA or typeB is List.
    1. typeA and typeB must both be List.
    2. Let typeA be the item type of typeA
    3. Let typeB be the item type of typeB
    4. Repeat from step 3.
  5. If typeA or typeB is Scalar or Enum.
    1. typeA and typeB must be the same type.
  6. Assert: typeA and typeB are both composite types.
  7. Let mergedSet be the result of adding the selection set of fieldA and the selection set of fieldB .
  8. Let fieldsForName be the set of selections with a given response name in mergedSet including visiting fragments and inline fragments.
  9. Given each pair of members subfieldA and subfieldB in fieldsForName :
    1. SameResponseShape ( subfieldA , subfieldB ) must be true.

Explanatory Text

If multiple field selections with the same response names are encountered during execution, the field and arguments to execute and the resulting value should be unambiguous. Therefore any two field selections which might both be encountered for the same object are only valid if they are equivalent.

For simple hand‐written GraphQL, this rule is obviously a clear developer error, however nested fragments can make this difficult to detect manually.

The following selections correctly merge:

fragment mergeIdenticalFields on Dog {
  name
  name
}

fragment mergeIdenticalAliasesAndFields on Dog {
  otherName: name
  otherName: name
}

The following is not able to merge:

fragment conflictingBecauseAlias on Dog {
  name: nickname
  name
}

Identical arguments are also merged if they have identical arguments. Both values and variables can be correctly merged.

For example the following correctly merge:

fragment mergeIdenticalFieldsWithIdenticalArgs on Dog {
  doesKnowCommand(dogCommand: SIT)
  doesKnowCommand(dogCommand: SIT)
}

fragment mergeIdenticalFieldsWithIdenticalValues on Dog {
  doesKnowCommand(dogCommand: $dogCommand)
  doesKnowCommand(dogCommand: $dogCommand)
}

The following do not correctly merge:

fragment conflictingArgsOnValues on Dog {
  doesKnowCommand(dogCommand: SIT)
  doesKnowCommand(dogCommand: HEEL)
}

fragment conflictingArgsValueAndVar on Dog {
  doesKnowCommand(dogCommand: SIT)
  doesKnowCommand(dogCommand: $dogCommand)
}

fragment conflictingArgsWithVars on Dog {
  doesKnowCommand(dogCommand: $varOne)
  doesKnowCommand(dogCommand: $varTwo)
}

fragment differingArgs on Dog {
  doesKnowCommand(dogCommand: SIT)
  doesKnowCommand
}

The following fields would not merge together, however both cannot be encountered against the same object, so they are safe:

fragment safeDifferingFields on Pet {
  ... on Dog {
    volume: barkVolume
  }
  ... on Cat {
    volume: meowVolume
  }
}

fragment safeDifferingArgs on Pet {
  ... on Dog {
    doesKnowCommand(dogCommand: SIT)
  }
  ... on Cat {
    doesKnowCommand(catCommand: JUMP)
  }
}

However, the field responses must be shapes which can be merged. For example, scalar values must not differ. In this example,someValuemight be aStringor anInt:

fragment conflictingDifferingResponses on Pet {
  ... on Dog {
    someValue: nickname
  }
  ... on Cat {
    someValue: meowVolume
  }
}

results matching ""

    No results matching ""