git.iko.soy/rowtype-yoga/purescript-graphql
on master help sign in
Add some more general documentation
commit331e490c25738514e6cc13e484374e9cbec66c73 authorhendrikniemann <h.neverman@web.de> dateFri 28 May 2021, 18:59 (5 years ago) parent3cda99b
2 files changed+144
docs/object_types.md+52 docs/scalar_types.md+92
docs/object_types.mdnew file+52
@@ -0,0 +1,52 @@
1+# Obejct Types
2+
3+## About object types
4+
5+Object types are used to represent complex data structures.
6+Objects map very closely to records or structures in other programming languages.
7+In SDL, object types are defined in a way that is very similar to PureScript records or TypeScript objects:
8+
9+```graphql
10+type Todo {
11+ id: ID!
12+ title: String!
13+ createdAt: DateTime!
14+ completedAt: DateTime
15+}
16+```
17+
18+An object type on the API level describes an offer to the client.
19+Which fields are returned to the client depends on the query.
20+
21+## Creating an object type
22+
23+Imagine we want to build a simple object type for the following record type in PureScript:
24+
25+```purescript
26+type Todo =
27+ { id :: Int
28+ , title :: String
29+ , createdAt :: DateTime
30+ , completedAt :: Maybe DateTime
31+ }
32+```
33+
34+We start with an empty object type by giving it a name:
35+
36+```purescript
37+todoType :: GQL.ObjectType Context Todo
38+todoType = GQL.objectType "Todo"
39+```
40+
41+In the type signature, we define the context in which our GraphQL operations are executed.
42+This can be any monad with a `MonadError Error` instance, like `Aff`, `Effect`, `Either Error`, etc.
43+Obviously, if we want to run side effects, we need an appropriate monad.
44+I recommend to create a fitting monad transformer stack and exporting the type to your object types.
45+For now we can use `Effect`, which allows us to run simple effects like logging.
46+
47+The second type
48+
49+```purescript
50+todoType :: GQL.ObjectType Effect Todo
51+todoType = GQL.objectType "Todo"
52+```
docs/scalar_types.mdnew file+92
@@ -0,0 +1,92 @@
1+# Scalar Types
2+
3+## Leaf Types
4+
5+In GraphQL, Leaf Types are types that turn into a specific value and have no connections to other types (other than their parent node).
6+There are two GraphQL kinds that can produce leaf types: The Scalar and the Enumeration.
7+Enum types are used for types that have a finite set of values and serialize by mapping to a finite set of JSON string values.
8+Scalar types, on the other hand, can serialize to any JSON value.
9+This includes JSON lists and maps, but usually scalars should use the JSON primitive types for representation: String, Number, Boolean.
10+
11+## Built in Scalar Types
12+
13+The GraphQL Specification lists five scalar types, that need to be supported by every GraphQL implementation.
14+These scalars are probably enough to get you started in your project.
15+
16+- The `Int` scalar is used for [natural numbers in the Int32 range](http://spec.graphql.org/June2018/#sec-Int).
17+- The `Float` type represents [signed double‐precision fractional values](http://spec.graphql.org/June2018/#sec-Float).
18+- The `String` scalar represents [UTF-8 encoded strings](http://spec.graphql.org/June2018/#sec-String).
19+- The `Boolean` scalar represents [boolean logic truth values](http://spec.graphql.org/June2018/#sec-Boolean).
20+- And finally the `ID` scalar is used for [unique identifiers](http://spec.graphql.org/June2018/#sec-ID). It is always serialised as a JSON string, but can also accept integer values from client queries.
21+
22+PureScript GraphQL provides implementations for these scalars in the `GraphQL.Builtin.Scalar` module.
23+As GraphQL types are values in PureScript, they use lower case identifiers: `int`, `float`, `string`, `boolean` and `id`.
24+They are exported as well from the `GraphQL` main module.
25+
26+## Defining custom Scalar Types
27+
28+Sometimes, the built in scalar types are not enough and you want to represent a custom type together with input validation.
29+One great example is the `DateTime` scalar.
30+
31+> **Note:**
32+> You can find the full code for this example [here](https://github.com/hendrikniemann/purescript-graphql-fullstack-example/blob/master/backend/src/Schema/DateTime.purs).
33+
34+The predefined scalars are using the `ScalarType` newtype to implement the serialization and deserialization logic.
35+We can do the same to provide our own custom scalars.
36+If we want to build a scalar that serializes `DateTime` from `Data.DateTime` into a string in ISO 8601 format (`YYYY-MM-DDTHH:mm:ss.SSSZ`), we have to provide two functions:
37+
38+- `parseDateTime` which takes a string and returns either an error message or a valid `DateTime`.
39+- `formatDateTime` which turns a `DateTime` into a string.
40+
41+Using `Data.Formatter.DateTime`, we can easily write these functions:
42+
43+```purescript
44+parseDateTime :: String -> Either String DateTime
45+parseDateTime = unformat dateFormat
46+
47+formatDateTime :: DateTime -> String
48+formatDateTime = format dateFormat
49+
50+dateFormat ∷ Formatter
51+dateFormat = parseFormatString "YYYY-MM-DDTHH:mm:ss.SSSZ" # unsafePartial fromRight
52+```
53+
54+With these two helper functions we can now implement the functions needed by the scalar:
55+
56+### `parseLiteral`
57+
58+`parseLiteral` is called when the scalar is used in an argument in a query and the value is supplied inline as a literal.
59+Here we have to deal with the different literal types that exist in GraphQL.
60+In our case we only want to accept `StringValueNode`s and error on everything else.
61+We can then parse the value using the `parseDateTime` function above.
62+
63+```purescript
64+parseLiteral (AST.StringValueNode { value }) = parseDateTime value
65+parseLiteral _ = Left "Expected string literal node for input type date time."
66+```
67+
68+> Usually types only work for a single type of literal but it is totally possible to parse different types of literals if you want to do so.
69+> It can also be an opportunity to implement more specific error messages.
70+
71+### `parseValue`
72+
73+`parseValue` is called whenever a variable of our scalar type is supplied.
74+In this case we have to react to a JSON value. This is easy with _Argonaut_:
75+
76+```purescript
77+parseValue = Json.caseJsonString (Left "Dates must be supplied as ISO strings.") parseDateTime
78+```
79+
80+### `serialize`
81+
82+In `serialize` we have to do the opposite:
83+Turn a `DateTime` value into a JSON value.
84+Again, we are using _Argonaut_ and our helper function `formatDateTime` to compose the final function.
85+
86+```purescript
87+serialize = formatDateTime >>> Json.fromString
88+```
89+
90+!> Scalars in PureScript are designed to be as typesafe and pure as possible.
91+Therefore `serialize` is not allowed to have side effects or return an error.
92+All potential errors must be dealt with in the field resolver.