summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthías Páll Gissurarson <mpg@mpg.is>2016-03-09 01:07:57 +0100
committerMatthías Páll Gissurarson <mpg@mpg.is>2016-03-14 01:01:20 +0100
commitb74278cd19d900d1397e35b85f7b80d70cd574f2 (patch)
tree17b7282544f73c9c2f2cec404f0d3fab1896bbe6
parentd8a731fe30ce800ac8347a902f38373d6cf689b2 (diff)
downloadgraphql-b74278cd19d900d1397e35b85f7b80d70cd574f2.tar.gz
Added a tutorial, based on graphql-js and servant documentation.
-rw-r--r--docs/tutorial/Makefile4
-rw-r--r--docs/tutorial/tutorial.css3
-rw-r--r--docs/tutorial/tutorial.lhs150
-rw-r--r--docs/tutorial/tutorial.rst176
4 files changed, 333 insertions, 0 deletions
diff --git a/docs/tutorial/Makefile b/docs/tutorial/Makefile
new file mode 100644
index 0000000..04d8d71
--- /dev/null
+++ b/docs/tutorial/Makefile
@@ -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
diff --git a/docs/tutorial/tutorial.css b/docs/tutorial/tutorial.css
new file mode 100644
index 0000000..831b73d
--- /dev/null
+++ b/docs/tutorial/tutorial.css
@@ -0,0 +1,3 @@
+body {
+ padding: 0 20px;
+}
diff --git a/docs/tutorial/tutorial.lhs b/docs/tutorial/tutorial.lhs
new file mode 100644
index 0000000..387d14d
--- /dev/null
+++ b/docs/tutorial/tutorial.lhs
@@ -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.
diff --git a/docs/tutorial/tutorial.rst b/docs/tutorial/tutorial.rst
new file mode 100644
index 0000000..1c8b5ff
--- /dev/null
+++ b/docs/tutorial/tutorial.rst
@@ -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.