git.iko.soy/rowtype-yoga/purescript-graphql
on master help sign in
Add union types and intro to docs
commit47fcf5dec6adbae9c99bd441a286bcc0f168145e authorhendrikniemann <h.neverman@web.de> dateWed 23 Sep 2020, 18:30 (6 years ago) parent95dcfcb
4 files changed+145−2
docs/_sidebar.md+2 docs/intro_to_graphql.md+43 docs/union_types.md+91 docs/version_2.md+9−2
docs/_sidebar.md+2
@@ -2,5 +2,7 @@
22
33 - [Introduction](README.md)
44 - [What's new in v2?](version_2.md)
5+ - [Intro To GraphQL](intro_to_graphql.md)
56 - [Getting Started](getting_started.md)
67 - [Building the HTTP server](http_server.md)
8+ - [Union Types and Interfaces](union_types.md)
docs/intro_to_graphql.mdnew file+43
@@ -0,0 +1,43 @@
1+# A functional programmers guide to GraphQL
2+
3+> In this guide we will have a look at GraphQL coming from a functional programming background.
4+> It is very brief because I believe the best way of learning GraphQL is through building and exploring.
5+> Instead, this section is supposed to teach you just enough to get started using PureScript GraphQL
6+
7+GraphQL is a query language for APIs that expose graph-like data structures.
8+A GraphQL API exposes all available data and operations in a giant graph.
9+The API consumer then uses GraphQL to select a subset of the data (a sub-graph).
10+Compared to other (graph) query languages, e.g. Cypher for Neo4j or SQL, GraphQL is a rather weak language that leaves room for custom implementation specific logic.
11+A GraphQL query mostly only consists of _selection sets_, _fields_ and _field arguments_.
12+
13+## GraphQL schema and type system
14+
15+Every GraphQL endpoint exposes exactly one schema.
16+The schema is a description of which queries can be executed on the GraphQL API.
17+GraphQL has a simple type system to describe this structure.
18+This type system features scalars for promitive types, object types for record structures and union types for sum types.
19+
20+## GraphQL resolver model
21+
22+There are many ways how a GraphQL query can be translated into a corresponding result.
23+PureScript GraphQL uses the well established resolver model.
24+In the resolver model, every field is paired with a function that describes how the provided field arguments together with the parent value form the field's value.
25+In PureScript GraphQL, a field can also perform some form of side effects, if the schema allows for it.
26+Let's look at some simple resolver examples:
27+
28+```purescript
29+-- Root resolver loads row from database
30+todo :: { id :: String } -> Unit -> Aff (Todo { title :: String, isCompleted :: Boolean })
31+todo args parent = loadTodoById args.id
32+
33+-- Field with no arguments resolves to parent field
34+isCompleted :: {} -> Todo { title :: String, isCompleted :: Boolean } -> Aff String
35+isCompleted args (Todo { isCompleted }) = pure isCompleted
36+```
37+
38+## GraphQL over HTTP
39+
40+The GraphQL specification itself deliberately leaves out specifics about the transport layer.
41+GraphQL queries can be sent via HTTP, websockets or any other text format imaginable.
42+On the web, we usually find GraphQL servers that use HTTP for queries and mutations and websockets for subscriptions.
43+PureScript GraphQL does not provide transport layer functionality, but we are going to build an HTTP server in one of the chapters of this documentation.
docs/union_types.mdnew file+91
@@ -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+```
docs/version_2.md+9−2
@@ -13,7 +13,7 @@ But I have gathered feedback from the community and came up with these interesti
1313## Free Choice of Execution Context
1414
1515This is the biggest change and pretty much the sole motivator for the rewrite.
16−The GraphQL result can now be calculated inside of the context of any monad.
16+The GraphQL result can now be calculated inside of the context of any monad (that supports errors).
1717Usually the execution of a schema is an effectful computation.
1818The user of the library is now completely free to use any effect monad of their choice as long as it provides a `MonadError Error` implementation (like e.g. `Aff` or `Effect`).
1919If the execution is completely pure one can even use `Either Error` to create side-effectless synchronious schemas.
@@ -33,4 +33,11 @@ Tired of arrays?
3333You prefer your good old `List`?
3434Or sometimes you just want to directly return a `Map` from a resolver?
3535No problem!
36−PureScript GraphQL will painlessly traverse your data structure into a JSON array.
36+PureScript GraphQL will painlessly fold your data structure into a JSON array.
37+`Traversable` is needed to collect the results of the child resolvers into the context monad.
38+
39+## New functional DSL
40+
41+In PureScript GraphQL v2 we introduce a new embedded DSL to create GraphQL types.
42+All data structures used to create a schema are now plain immutable PureScript types, that can be combined and changed with the provided functions and operators.
43+This allows us to write interesting abstractions on top of PureScript GraphQL.