Added a tutorial, based on graphql-js and servant documentation.
This commit is contained in:
parent
d8a731fe30
commit
b74278cd19
4
docs/tutorial/Makefile
Normal file
4
docs/tutorial/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
default:
|
||||
pandoc -f markdown+lhs+yaml_metadata_block --highlight-style=haddock -S -c "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" --section-divs -c tutorial.css --toc --standalone -t html5 -o tutorial.html tutorial.lhs
|
||||
pandoc -f markdown+lhs+yaml_metadata_block --highlight-style=haddock --toc --standalone -t rst -o tutorial.rst tutorial.lhs
|
||||
pandoc -f markdown+lhs+yaml_metadata_block --highlight-style=haddock --toc --standalone -t latex -o tutorial.pdf tutorial.lhs
|
3
docs/tutorial/tutorial.css
Normal file
3
docs/tutorial/tutorial.css
Normal file
@ -0,0 +1,3 @@
|
||||
body {
|
||||
padding: 0 20px;
|
||||
}
|
150
docs/tutorial/tutorial.lhs
Normal file
150
docs/tutorial/tutorial.lhs
Normal file
@ -0,0 +1,150 @@
|
||||
---
|
||||
title: GraphQL Haskell Tutorial
|
||||
---
|
||||
|
||||
|
||||
== Getting started ==
|
||||
|
||||
Welcome to graphql-haskell!
|
||||
|
||||
We have written a small tutorial to help you (and ourselves) understand the graphql package.
|
||||
|
||||
Since this file is a literate haskell file, we start by importing some dependencies.
|
||||
|
||||
> {-# LANGUAGE OverloadedStrings #-}
|
||||
> {-# LANGUAGE LambdaCase #-}
|
||||
> module Main where
|
||||
>
|
||||
> import Prelude hiding (empty, putStrLn)
|
||||
> import Data.GraphQL
|
||||
> import Data.GraphQL.Schema
|
||||
> import qualified Data.GraphQL.Schema as Schema
|
||||
>
|
||||
> import Control.Applicative
|
||||
> import Data.Text hiding (empty)
|
||||
> import Data.Aeson
|
||||
> import Data.ByteString.Lazy.Char8 (putStrLn)
|
||||
>
|
||||
> import Data.Time
|
||||
>
|
||||
> import Debug.Trace
|
||||
|
||||
=== First example ===
|
||||
|
||||
Now, as our first example, we are going to look at the
|
||||
example from [graphql.js](https://github.com/graphql/graphql-js).
|
||||
|
||||
First we build a GraphQL schema.
|
||||
|
||||
> schema1 :: Alternative f => Schema f
|
||||
> schema1 = Schema [hello]
|
||||
>
|
||||
> hello :: Alternative f => Resolver f
|
||||
> hello = Schema.scalar "hello" ("it's me" :: Text)
|
||||
|
||||
This defines a simple schema with one type and one field, that resolves to a fixed value.
|
||||
|
||||
Next we define our query.
|
||||
|
||||
> query1 :: Text
|
||||
> query1 = "{ hello }"
|
||||
|
||||
|
||||
To run the query, we call the `graphql` with the schema and the query.
|
||||
|
||||
> main1 :: IO ()
|
||||
> main1 = putStrLn =<< encode <$> graphql schema1 query1
|
||||
|
||||
This runs the query by fetching the one field defined,
|
||||
returning
|
||||
|
||||
```{"data" : {"hello":"it's me"}}```
|
||||
|
||||
|
||||
|
||||
=== Monadic actions ===
|
||||
|
||||
For this example, we're going to be using time.
|
||||
|
||||
> schema2 :: Schema IO
|
||||
> schema2 = Schema [time]
|
||||
>
|
||||
> time :: Resolver IO
|
||||
> time = Schema.scalarA "time" $ \case
|
||||
> [] -> do t <- getCurrentTime
|
||||
> return $ show t
|
||||
> _ -> empty
|
||||
|
||||
This defines a simple schema with one type and one field,
|
||||
which resolves to the current time.
|
||||
|
||||
Next we define our query.
|
||||
|
||||
> query2 :: Text
|
||||
> query2 = "{ time }"
|
||||
>
|
||||
> main2 :: IO ()
|
||||
> main2 = putStrLn =<< encode <$> graphql schema2 query2
|
||||
|
||||
This runs the query, returning the current time
|
||||
|
||||
```{"data": {"time":"2016-03-08 23:28:14.546899 UTC"}}```
|
||||
|
||||
|
||||
=== Errors ===
|
||||
|
||||
Errors are handled according to the spec,
|
||||
with fields that cause erros being resolved to `null`,
|
||||
and an error being added to the error list.
|
||||
|
||||
An example of this is the following query:
|
||||
|
||||
> queryShouldFail :: Text
|
||||
> queryShouldFail = "{ boyhowdy }"
|
||||
|
||||
Since there is no `boyhowdy` field in our schema, it will not resolve,
|
||||
and the query will fail, as we can see in the following example.
|
||||
|
||||
> mainShouldFail :: IO ()
|
||||
> mainShouldFail = do
|
||||
> r <- graphql schema1 query1
|
||||
> putStrLn $ encode r
|
||||
> putStrLn "This will fail"
|
||||
> r <- graphql schema1 queryShouldFail
|
||||
> putStrLn $ encode r
|
||||
>
|
||||
|
||||
This outputs:
|
||||
|
||||
```
|
||||
{"data": {"hello": "it's me"}}
|
||||
This will fail
|
||||
{"data": {"boyhowdy": null}, "errors":[{"message": "the field boyhowdy did not resolve."}]}
|
||||
```
|
||||
|
||||
=== Combining resolvers ===
|
||||
|
||||
Now that we have two resolvers, we can define a schema which uses them both.
|
||||
|
||||
> schema3 :: Schema IO
|
||||
> schema3 = Schema [hello, time]
|
||||
>
|
||||
> query3 :: Text
|
||||
> query3 = "query timeAndHello { time hello }"
|
||||
>
|
||||
> main3 :: IO ()
|
||||
> main3 = putStrLn =<< encode <$> graphql schema3 query3
|
||||
|
||||
This queries for both time and hello, returning
|
||||
|
||||
```{ "data": {"hello":"it's me","time":"2016-03-08 23:29:11.62108 UTC"}}```
|
||||
|
||||
Notice that we can name our queries, as we did with `timeAndHello`. Since we have only been using single queries, we can use the shorthand `{ time hello}`, as we have been doing in the previous examples.
|
||||
|
||||
In GraphQL there can only be one operation per query.
|
||||
|
||||
|
||||
== Further examples ==
|
||||
|
||||
More examples on queries and a more complex schema can be found in the test directory,
|
||||
in the [Test.StarWars](../../tests/Test/StarWars) module. This includes a more complex schema, and more complex queries.
|
176
docs/tutorial/tutorial.rst
Normal file
176
docs/tutorial/tutorial.rst
Normal file
@ -0,0 +1,176 @@
|
||||
========================
|
||||
GraphQL Haskell Tutorial
|
||||
========================
|
||||
|
||||
.. contents::
|
||||
:depth: 3
|
||||
..
|
||||
|
||||
Getting started
|
||||
===============
|
||||
|
||||
Welcome to graphql-haskell!
|
||||
|
||||
We have written a small tutorial to help you (and ourselves) understand
|
||||
the graphql package.
|
||||
|
||||
Since this file is a literate haskell file, we start by importing some
|
||||
dependencies.
|
||||
|
||||
.. code:: haskell
|
||||
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE LambdaCase #-}
|
||||
module Main where
|
||||
|
||||
import Prelude hiding (empty, putStrLn)
|
||||
import Data.GraphQL
|
||||
import Data.GraphQL.Schema
|
||||
import qualified Data.GraphQL.Schema as Schema
|
||||
|
||||
import Control.Applicative
|
||||
import Data.Text hiding (empty)
|
||||
import Data.Aeson
|
||||
import Data.ByteString.Lazy.Char8 (putStrLn)
|
||||
|
||||
import Data.Time
|
||||
|
||||
import Debug.Trace
|
||||
|
||||
First example
|
||||
-------------
|
||||
|
||||
Now, as our first example, we are going to look at the example from
|
||||
`graphql.js <https://github.com/graphql/graphql-js>`__.
|
||||
|
||||
First we build a GraphQL schema.
|
||||
|
||||
.. code:: haskell
|
||||
|
||||
schema1 :: Alternative f => Schema f
|
||||
schema1 = Schema [hello]
|
||||
|
||||
hello :: Alternative f => Resolver f
|
||||
hello = Schema.scalar "hello" ("it's me" :: Text)
|
||||
|
||||
This defines a simple schema with one type and one field, that resolves
|
||||
to a fixed value.
|
||||
|
||||
Next we define our query.
|
||||
|
||||
.. code:: haskell
|
||||
|
||||
query1 :: Text
|
||||
query1 = "{ hello }"
|
||||
|
||||
To run the query, we call the ``graphql`` with the schema and the query.
|
||||
|
||||
.. code:: haskell
|
||||
|
||||
main1 :: IO ()
|
||||
main1 = putStrLn =<< encode <$> graphql schema1 query1
|
||||
|
||||
This runs the query by fetching the one field defined, returning
|
||||
|
||||
``{"data" : {"hello":"it's me"}}``
|
||||
|
||||
Monadic actions
|
||||
---------------
|
||||
|
||||
For this example, we're going to be using time.
|
||||
|
||||
.. code:: haskell
|
||||
|
||||
schema2 :: Schema IO
|
||||
schema2 = Schema [time]
|
||||
|
||||
time :: Resolver IO
|
||||
time = Schema.scalarA "time" $ \case
|
||||
[] -> do t <- getCurrentTime
|
||||
return $ show t
|
||||
_ -> empty
|
||||
|
||||
This defines a simple schema with one type and one field, which resolves
|
||||
to the current time.
|
||||
|
||||
Next we define our query.
|
||||
|
||||
.. code:: haskell
|
||||
|
||||
query2 :: Text
|
||||
query2 = "{ time }"
|
||||
|
||||
main2 :: IO ()
|
||||
main2 = putStrLn =<< encode <$> graphql schema2 query2
|
||||
|
||||
This runs the query, returning the current time
|
||||
|
||||
``{"data": {"time":"2016-03-08 23:28:14.546899 UTC"}}``
|
||||
|
||||
Errors
|
||||
------
|
||||
|
||||
Errors are handled according to the spec, with fields that cause erros
|
||||
being resolved to ``null``, and an error being added to the error list.
|
||||
|
||||
An example of this is the following query:
|
||||
|
||||
.. code:: haskell
|
||||
|
||||
queryShouldFail :: Text
|
||||
queryShouldFail = "{ boyhowdy }"
|
||||
|
||||
Since there is no ``boyhowdy`` field in our schema, it will not resolve,
|
||||
and the query will fail, as we can see in the following example.
|
||||
|
||||
.. code:: haskell
|
||||
|
||||
mainShouldFail :: IO ()
|
||||
mainShouldFail = do
|
||||
r <- graphql schema1 query1
|
||||
putStrLn $ encode r
|
||||
putStrLn "This will fail"
|
||||
r <- graphql schema1 queryShouldFail
|
||||
putStrLn $ encode r
|
||||
|
||||
This outputs:
|
||||
|
||||
::
|
||||
|
||||
{"data": {"hello": "it's me"}}
|
||||
This will fail
|
||||
{"data": {"boyhowdy": null}, "errors":[{"message": "the field boyhowdy did not resolve."}]}
|
||||
|
||||
Combining resolvers
|
||||
-------------------
|
||||
|
||||
Now that we have two resolvers, we can define a schema which uses them
|
||||
both.
|
||||
|
||||
.. code:: haskell
|
||||
|
||||
schema3 :: Schema IO
|
||||
schema3 = Schema [hello, time]
|
||||
|
||||
query3 :: Text
|
||||
query3 = "query timeAndHello { time hello }"
|
||||
|
||||
main3 :: IO ()
|
||||
main3 = putStrLn =<< encode <$> graphql schema3 query3
|
||||
|
||||
This queries for both time and hello, returning
|
||||
|
||||
``{ "data": {"hello":"it's me","time":"2016-03-08 23:29:11.62108 UTC"}}``
|
||||
|
||||
Notice that we can name our queries, as we did with ``timeAndHello``.
|
||||
Since we have only been using single queries, we can use the shorthand
|
||||
``{ time hello}``, as we have been doing in the previous examples.
|
||||
|
||||
In GraphQL there can only be one operation per query.
|
||||
|
||||
Further examples
|
||||
================
|
||||
|
||||
More examples on queries and a more complex schema can be found in the
|
||||
test directory, in the `Test.StarWars <../../tests/Test/StarWars>`__
|
||||
module. This includes a more complex schema, and more complex queries.
|
Loading…
Reference in New Issue
Block a user