Skip to content

Commit 478adf3

Browse files
authored
Alternative input union workaround (#744)
* Alternative input union workaround * Add snakes to example
1 parent d78a4ce commit 478adf3

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

rfcs/InputUnion.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ input AnimalDropOffInput {
6565
}
6666
```
6767

68-
This allows non-sensical mutations to pass GraphQL validation, for example representing an animal that is both a `Cat` and a `Dog`.
68+
This allows nonsensical mutations to pass GraphQL validation, for example representing an animal that is both a `Cat` and a `Dog`.
6969

7070
```graphql
7171
mutation {
@@ -103,6 +103,31 @@ In addition, relying on this layer of abstraction means that this domain must be
103103
}
104104
```
105105

106+
Another approach is to use an input type with a discriminator and input fields for all possible member types.
107+
108+
```graphql
109+
mutation {
110+
logAnimalDropOff(
111+
location: "Portland, OR"
112+
animals: [
113+
{type: CAT, name: "Buster", age: 3, livesLeft: 7},
114+
{type: DOG, name: "Ripple", age: 2, breed: WHIPPET}
115+
]
116+
)
117+
}
118+
119+
input AnimalDropOffInput {
120+
type: AnimalType!
121+
name: String!
122+
age: Int!
123+
breed: DogBreed # only applies when type = DOG
124+
livesLeft: Int # only applies when type = CAT
125+
venom: VenomType # only applies when type = SNAKE
126+
}
127+
```
128+
129+
This results in more consistent modeling between input & output but still allows nonsensical inputs to pass GraphQL validation.
130+
106131
Another common approach is to provide a unique mutation for every type. A schema employing this technique might have `logCatDropOff`, `logDogDropOff` and `logSnakeDropOff` mutations. This removes the potential for modeling non-sensical situations, but it explodes the number of mutations in a schema, making the schema less accessible. If the type is nested inside other inputs, this approach simply isn't feasable.
107132

108133
These workarounds only get worse at scale. Real world GraphQL schemas can have dozens if not hundreds of possible types for a single `Interface` or `Union`.
@@ -158,6 +183,9 @@ The topic has also been extensively explored in Computer Science more generally.
158183
* [Wikipedia: Tagged Union](https://en.wikipedia.org/wiki/Tagged_union)
159184
* [C2 Wiki: Nominative And Structural Typing](http://wiki.c2.com/?NominativeAndStructuralTyping)
160185

186+
There are also libraries that mimic this functionality in GraphQL:
187+
188+
* [graphql-union-input-type](https://github.com/Cardinal90/graphql-union-input-type)
161189

162190
# 🛠 Use Cases
163191

@@ -322,6 +350,7 @@ input union IU = { x: String } | { y: Int }
322350

323351
* ✂️ Objection: The addition of a polymorphic input type shouldn't depend on the ability to change the type of an existing field or an existing usage pattern. One can always add new fields that leverage new features.
324352
* ✂️ Objection: May break variable names? Only avoided with care
353+
* ✂️ Objection: There are different ways people are working around the lack of input unions so it likely won't be feasible to come up with a non-breaking migration path for all of them.
325354

326355
| [1][solution-1] | [2][solution-2] | [3][solution-3] | [4][solution-4] | [5][solution-5] |
327356
|----|----|----|----|----|

0 commit comments

Comments
 (0)