@@ -0,0 +1,91 @@
1+# Union Types and Interfaces
2+
3+## Sum types in GraphQL
4+
5+Sometimes in our API, we want to return a values of different types.
6+Imagine the following example:
7+In a Twitter-like social media app, we have a stream of posts.
8+Posts can contain some media, either a link/url, an image or a video.
9+
10+In PureScript we could model it like this:
11+
12+```purescript
13+newtype Post = Post { id :: Int, body :: String, media :: Maybe Media }
14+
15+data Media
16+ = Link { url :: String, title :: String }
17+ | Image { url :: String, altText :: Maybe String }
18+ | Video { url :: String, length :: Int }
19+```
20+
21+In GraphQL, we can use the union type to create a sum type of object types.
22+
23+```graphql
24+type Post {
25+ id: ID!
26+ body: String!
27+ media: Media
28+}
29+
30+type Link {
31+ url: String!
32+ title: String!
33+}
34+
35+type Image {
36+ url: String!
37+ altText: String
38+}
39+
40+type Video {
41+ url: String!
42+ length: Int!
43+}
44+
45+union Media = Link | Image | Video
46+```
47+
48+An alternative way to create sum types are `Variant`s.
49+Variants use row types instead and let us create more reusable functions.
50+Variants also allow for type level programming.
51+
52+```purescript
53+type MediaVariant = Variant
54+ ( link :: { url :: String, title :: String }
55+ , image :: { url :: String, altText :: Maybe String }
56+ , video :: { url :: String, length :: Int }
57+ )
58+```
59+
60+## Using union types in PureScript GraphQL
61+
62+Variant types are not that easy to use, because we have to use `SProxy` to handle type level strings in our code.
63+But they allow PureScript GraphQL to generate a Variant type, when we supply a record of object types for the union type.
64+To build a union type in PureScript GraphQL, we use the `union` function from `GraphQL.Type` (here imported as `GQL`):
65+
66+```purescript
67+-- This assumes you already built the following object types:
68+-- linkType :: GQL.ObjectType Context { url :: String, title :: String }
69+-- imageType :: GQL.ObjectType Context { url :: String, altText :: Maybe String }
70+-- videoType :: GQL.ObjectType Context { url :: String, length :: Int }
71+
72+mediaType :: GQL.UnionType Context MediaVariant
73+mediaType = GQL.union "Media" { link: linkType, image: imageType, video: videoType }
74+```
75+
76+Notice how the record type used in the definition is very similar to the variant type.
77+
78+```purescript
79+record :: Record
80+ ( link :: GQL.ObjectType Context { url :: String, title :: String }
81+ , image :: GQL.ObjectType Context { url :: String, altText :: Maybe String }
82+ , video :: GQL.ObjectType Context { url :: String, length :: Int }
83+ )
84+record = { link: linkType, image: imageType, video: videoType }
85+
86+type MediaVariant = Variant
87+ ( link :: { url :: String, title :: String }
88+ , image :: { url :: String, altText :: Maybe String }
89+ , video :: { url :: String, length :: Int }
90+ )
91+```