You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: rfcs/InputUnion.md
+114-2Lines changed: 114 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,8 +18,120 @@ To help bring this idea to reality, you can contribute through two channels:
18
18
19
19
## Problem Statement
20
20
21
-
TODO:
22
-
*[ ] Describe at a high level the problem that Input Union is trying to solve.
21
+
GraphQL currently provides polymorphic types that enable schema authors to model complex **Object** types that have multiple shapes while remaining type-safe, but lacks an equivilant capability for **Input** types.
22
+
23
+
Over the years there have been numerous proposals from the community to add a polymorphic input type. Without such a type, schema authors have resorted to a handful of work-arounds to model their domains. These work-arounds have led to schemas that aren't as expressive as they could be, and schemas where mutations that ideally mirror queries are forced to be modeled differently.
24
+
25
+
## Problem Sketch
26
+
27
+
To understand the problem space a little more, we'll sketch out an example that explores a domain from the perspective of a Query and a Mutation. However, it's important to note that the problem is not limited to mutations, since `Input` types are used in field arguments for any GraphQL operation type.
28
+
29
+
Let's imagine an animal shelter for our example. When querying for a list of the animals, it's easy to see how abstract types are useful - we can get data specific to the type of the animal easily.
30
+
31
+
```graphql
32
+
{
33
+
animalShelter(location: "Portland, OR") {
34
+
animals {
35
+
__typename
36
+
name
37
+
age
38
+
...onCat { livesLeft }
39
+
...onDog { breed }
40
+
...onSnake { venom }
41
+
}
42
+
}
43
+
}
44
+
```
45
+
46
+
However, when we want to submit data, we can't use an `interface` or `union`, so we must model around that.
47
+
48
+
One technique commonly used to is a **tagged union** pattern. This essentially boils down to a "wrapper" input that isolates each type into it's own field. The field name takes on the convention of representing the type.
49
+
50
+
```graphql
51
+
mutation {
52
+
logAnimalDropOff(
53
+
location: "Portland, OR"
54
+
animals: [
55
+
{cat: {name: "Buster", age: 3, livesLeft: 7}}
56
+
]
57
+
)
58
+
}
59
+
```
60
+
61
+
Unfortunately, this opens up a set of problems, since the Tagged union input type actually contains many fields, any of which could be submitted.
62
+
63
+
```graphql
64
+
inputAnimalDropOffInput {
65
+
cat: CatInput
66
+
dog: DogInput
67
+
snake: SnakeInput
68
+
}
69
+
```
70
+
71
+
Thisallowsnon-sensicalmutationstopassGraphQLvalidation, forexamplerepresentingananimalthatisbotha `Cat` anda `Dog`.
72
+
73
+
```graphql
74
+
mutation {
75
+
logAnimalDropOff(
76
+
location: "Portland, OR"
77
+
animals: [
78
+
{
79
+
cat: {name: "Buster", age: 3, livesLeft: 7},
80
+
dog: {name: "Ripple", age: 2, breed: WHIPPET}
81
+
}
82
+
]
83
+
)
84
+
}
85
+
```
86
+
87
+
In addition, relying on this layer of abstraction means that this domain must be modelled differently across input & output. This can put a larger burden on the developer interacting with the schema, both in terms of lines of code and complexity.
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.
110
+
111
+
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`.
112
+
113
+
The goal of the **Input Union** is to bring a polymorphic type to Inputs. This would enable us to model situations where an input may be of different types in a type-safe and elegant manner, like we can with outputs.
114
+
115
+
```graphql
116
+
mutation {
117
+
logAnimalDropOff(
118
+
location: "Portland, OR"
119
+
120
+
# Problem: we need to determine the type of each Animal
121
+
animals: [
122
+
# This is meant to be a CatInput
123
+
{name: "Buster", age: 3, livesLeft: 7},
124
+
125
+
# This is meant to be a DogInput
126
+
{name: "Ripple", age: 2},
127
+
]
128
+
)
129
+
}
130
+
```
131
+
132
+
In this mutation, we encounter the main challenge of the **Input Union** - we need to determine the correct type of the data submitted.
133
+
134
+
A wide variety of solutions have been explored by the community, and they are outlined in detail in this document under [Possible Solutions](#Possible-Solutions).
0 commit comments