Skip to content

Commit 3034ac7

Browse files
Release 0.8.0 (#333)
* syntax * update readme * update * update * update index.md * update version number * update realese date * 2019
1 parent 7e117e6 commit 3034ac7

File tree

6 files changed

+196
-32
lines changed

6 files changed

+196
-32
lines changed

README.md

Lines changed: 85 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ _stack.yml_
2929
resolver: lts-14.8
3030

3131
extra-deps:
32-
- morpheus-graphql-0.7.1
32+
- morpheus-graphql-0.8.0
3333
```
3434
3535
As Morpheus is quite new, make sure stack can find morpheus-graphql by running `stack upgrade` and `stack update`
@@ -118,10 +118,7 @@ data Query m = Query
118118
data Deity = Deity
119119
{ fullName :: Text -- Non-Nullable Field
120120
, power :: Maybe Text -- Nullable Field
121-
} deriving (Generic)
122-
123-
instance GQLType Deity where
124-
type KIND Deity = OBJECT
121+
} deriving (Generic,GQLType)
125122
126123
data DeityArgs = DeityArgs
127124
{ name :: Text -- Required Argument
@@ -152,8 +149,6 @@ askDB :: Text -> Maybe Text -> IO (Either String Deity)
152149
askDB = ...
153150
```
154151

155-
Note that the type `a -> IORes b` is just Synonym for `a -> ExceptT String IO b`
156-
157152
To make this `Query` type available as an API, we define a `GQLRootResolver` and feed it to the Morpheus `interpreter`. A `GQLRootResolver` consists of `query`, `mutation` and `subscription` definitions, while we omit the latter for this example:
158153

159154
```haskell
@@ -236,14 +231,70 @@ To use union type, all you have to do is derive the `GQLType` class. Using Graph
236231

237232
```haskell
238233
data Character
239-
= DEITY Deity
240-
| HUMAN Human
241-
deriving (Generic)
234+
= data Character =
235+
CharacterDeity Deity -- Only <tyconName><conName> should generate direct link
236+
-- RECORDS
237+
| Creature { creatureName :: Text, creatureAge :: Int }
238+
--- Types
239+
| SomeDeity Deity
240+
| CharacterInt Int
241+
| SomeMutli Int Text
242+
--- ENUMS
243+
| Zeus
244+
| Cronus
245+
deriving (Generic, GQLType)
246+
```
247+
248+
where deity is and object
249+
250+
as you see there ar different kinds of unions. `morpheus` handles them all.
251+
252+
this type will be represented as
253+
254+
```gql
255+
union Character =
256+
Deity # unwrapped union: becouse Character + Deity = CharacterDeity
257+
| Creature
258+
| SomeDeity # wrapped union: becouse Character + Deity != SomeDeity
259+
| CharacterInt
260+
| SomeMutli
261+
| CharacterEnumObject # object wrapped for enums
262+
263+
type Creature {
264+
creatureName: String!
265+
creatureAge: Int!
266+
}
267+
268+
type SomeDeity {
269+
_0: Deity!
270+
}
271+
272+
type CharacterInt {
273+
_0: Int!
274+
}
275+
276+
type SomeMutli {
277+
_0: Int!
278+
_1: String!
279+
}
242280
243-
instance GQLType Character where
244-
type KIND Character = UNION
281+
# enum
282+
type CharacterEnumObject {
283+
enum: CharacterEnum!
284+
}
285+
286+
enum CharacterEnum {
287+
Zeus
288+
Cronus
289+
}
245290
```
246291

292+
- namespaced Unions: `CharacterDeity` where `Character` is TypeConstructor and `Deity` referenced object (not scalar) type: will be generate regular graphql Union
293+
294+
- for for all other unions will be generated new object type. for types without record syntaxt, fields will be automatally indexed.
295+
296+
- all empty constructors in union will be summed in type `<tyConName>Enum` (e.g `CharacterEnum`), this enum will be wrapped in `CharacterEnumObject` and added to union members.
297+
247298
### Scalar types
248299

249300
To use custom scalar types, you need to provide implementations for `parseValue` and `serialize` respectively.
@@ -286,6 +337,28 @@ screenshots from `Insomnia`
286337
![alt text](https://morpheusgraphql.com/assets/img/introspection/autocomplete.png "autocomplete")
287338
![alt text](https://morpheusgraphql.com/assets/img/introspection/type.png "type")
288339

340+
## Handling Errors
341+
342+
for errors you can use use either `liftEither` or `failRes`:
343+
at the and they have same result.
344+
345+
with `liftEither`
346+
347+
```haskell
348+
resolveDeity :: DeityArgs -> IORes e Deity
349+
resolveDeity DeityArgs {} = liftEither $ dbDeity
350+
351+
dbDeity :: IO Either Deity
352+
dbDeity = pure $ Left "db error"
353+
```
354+
355+
with `failRes`
356+
357+
```haskell
358+
resolveDeity :: DeityArgs -> IORes e Deity
359+
resolveDeity DeityArgs { } = failRes "db error"
360+
```
361+
289362
### Mutations
290363

291364
In addition to queries, Morpheus also supports mutations. The behave just like regular queries and are defined similarly:

changelog.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## [0.8.0] -
1+
## [0.8.0] - 15.12.2019
22

33
### Changed
44

docs/index.md

Lines changed: 105 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
---
22
layout: home
33
---
4-
54
# Morpheus GraphQL [![Hackage](https://img.shields.io/hackage/v/morpheus-graphql.svg)](https://hackage.haskell.org/package/morpheus-graphql) [![CircleCI](https://circleci.com/gh/morpheusgraphql/morpheus-graphql.svg?style=svg)](https://circleci.com/gh/morpheusgraphql/morpheus-graphql)
65

76
Build GraphQL APIs with your favourite functional language!
@@ -33,7 +32,7 @@ _stack.yml_
3332
resolver: lts-14.8
3433

3534
extra-deps:
36-
- morpheus-graphql-0.7.1
35+
- morpheus-graphql-0.8.0
3736
```
3837
3938
As Morpheus is quite new, make sure stack can find morpheus-graphql by running `stack upgrade` and `stack update`
@@ -122,10 +121,7 @@ data Query m = Query
122121
data Deity = Deity
123122
{ fullName :: Text -- Non-Nullable Field
124123
, power :: Maybe Text -- Nullable Field
125-
} deriving (Generic)
126-
127-
instance GQLType Deity where
128-
type KIND Deity = OBJECT
124+
} deriving (Generic,GQLType)
129125
130126
data DeityArgs = DeityArgs
131127
{ name :: Text -- Required Argument
@@ -156,8 +152,6 @@ askDB :: Text -> Maybe Text -> IO (Either String Deity)
156152
askDB = ...
157153
```
158154

159-
Note that the type `a -> IORes b` is just Synonym for `a -> ExceptT String IO b`
160-
161155
To make this `Query` type available as an API, we define a `GQLRootResolver` and feed it to the Morpheus `interpreter`. A `GQLRootResolver` consists of `query`, `mutation` and `subscription` definitions, while we omit the latter for this example:
162156

163157
```haskell
@@ -240,14 +234,70 @@ To use union type, all you have to do is derive the `GQLType` class. Using Graph
240234

241235
```haskell
242236
data Character
243-
= DEITY Deity
244-
| HUMAN Human
245-
deriving (Generic)
237+
= data Character =
238+
CharacterDeity Deity -- Only <tyconName><conName> should generate direct link
239+
-- RECORDS
240+
| Creature { creatureName :: Text, creatureAge :: Int }
241+
--- Types
242+
| SomeDeity Deity
243+
| CharacterInt Int
244+
| SomeMutli Int Text
245+
--- ENUMS
246+
| Zeus
247+
| Cronus
248+
deriving (Generic, GQLType)
249+
```
250+
251+
where deity is and object
252+
253+
as you see there ar different kinds of unions. `morpheus` handles them all.
246254

247-
instance GQLType Character where
248-
type KIND City = UNION
255+
this type will be represented as
256+
257+
```gql
258+
union Character =
259+
Deity # unwrapped union: becouse Character + Deity = CharacterDeity
260+
| Creature
261+
| SomeDeity # wrapped union: becouse Character + Deity != SomeDeity
262+
| CharacterInt
263+
| SomeMutli
264+
| CharacterEnumObject # object wrapped for enums
265+
266+
type Creature {
267+
creatureName: String!
268+
creatureAge: Int!
269+
}
270+
271+
type SomeDeity {
272+
_0: Deity!
273+
}
274+
275+
type CharacterInt {
276+
_0: Int!
277+
}
278+
279+
type SomeMutli {
280+
_0: Int!
281+
_1: String!
282+
}
283+
284+
# enum
285+
type CharacterEnumObject {
286+
enum: CharacterEnum!
287+
}
288+
289+
enum CharacterEnum {
290+
Zeus
291+
Cronus
292+
}
249293
```
250294

295+
- namespaced Unions: `CharacterDeity` where `Character` is TypeConstructor and `Deity` referenced object (not scalar) type: will be generate regular graphql Union
296+
297+
- for for all other unions will be generated new object type. for types without record syntaxt, fields will be automatally indexed.
298+
299+
- all empty constructors in union will be summed in type `<tyConName>Enum` (e.g `CharacterEnum`), this enum will be wrapped in `CharacterEnumObject` and added to union members.
300+
251301
### Scalar types
252302

253303
To use custom scalar types, you need to provide implementations for `parseValue` and `serialize` respectively.
@@ -290,6 +340,28 @@ screenshots from `Insomnia`
290340
![alt text](https://morpheusgraphql.com/assets/img/introspection/autocomplete.png "autocomplete")
291341
![alt text](https://morpheusgraphql.com/assets/img/introspection/type.png "type")
292342

343+
## Handling Errors
344+
345+
for errors you can use use either `liftEither` or `failRes`:
346+
at the and they have same result.
347+
348+
with `liftEither`
349+
350+
```haskell
351+
resolveDeity :: DeityArgs -> IORes e Deity
352+
resolveDeity DeityArgs {} = liftEither $ dbDeity
353+
354+
dbDeity :: IO Either Deity
355+
dbDeity = pure $ Left "db error"
356+
```
357+
358+
with `failRes`
359+
360+
```haskell
361+
resolveDeity :: DeityArgs -> IORes e Deity
362+
resolveDeity DeityArgs { } = failRes "db error"
363+
```
364+
293365
### Mutations
294366

295367
In addition to queries, Morpheus also supports mutations. The behave just like regular queries and are defined similarly:
@@ -445,7 +517,26 @@ with `fetch` you can fetch well typed response `GetHero`.
445517
jsonRes = <GraphQL APi>
446518
```
447519

448-
types can be generatet from `introspection` too:
520+
in this case, `jsonRes` is resolves a request into a response in some monad `m`.
521+
522+
A `fetch` resolver implementation against [a real API](https://swapi.graph.cool) may look like the following:
523+
524+
```haskell
525+
{-# LANGUAGE OverloadedStrings #-}
526+
527+
import Data.ByteString.Lazy (ByteString)
528+
import qualified Data.ByteString.Char8 as C8
529+
import Network.HTTP.Req
530+
531+
resolver :: String -> ByteString -> IO ByteString
532+
resolver tok b = runReq defaultHttpConfig $ do
533+
let headers = header "Content-Type" "application/json"
534+
responseBody <$> req POST (https "swapi.graph.cool") (ReqBodyLbs b) lbsResponse headers
535+
```
536+
537+
this is demonstrated in examples/src/Client/StarWarsClient.hs
538+
539+
types can be generated from `introspection` too:
449540

450541
```haskell
451542
defineByIntrospectionFile "./introspection.json"

examples/package.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ dependencies:
1616
- containers >= 0.4.2.1 && < 0.7
1717
- mtl >= 2.0 && <= 2.3
1818
- websockets >= 0.11.0 && <= 0.13
19-
- morpheus-graphql >= 0.7.1
19+
- morpheus-graphql >= 0.8.0
2020
- scotty
2121
- wai
2222
- warp

package.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: morpheus-graphql
2-
version: 0.7.1
2+
version: 0.8.0
33
github: "nalchevanidze/morpheus-graphql"
44
license: MIT
55
author: "Daviti Nalchevanidze"

specifications.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,6 @@ because there will be no unused fragment we will validate all sub fields.
129129

130130
### InputValue Errors:
131131

132-
- **expectedAFoundB**: input value does matches to schema type ✅
133-
- **undefinedField**: required field not found on input value ✅
134-
- **unknownField**: field does not exists on inputObject ✅
132+
- **expectedAFoundB**: input value does matches to schema type ✅ + 🧪
133+
- **undefinedField**: required field not found on input value ✅ + 🧪
134+
- **unknownField**: field does not exists on inputObject ✅ + 🧪

0 commit comments

Comments
 (0)