forked from OSS/graphql
Eugen Wissner
e24386402b
After the last commit there were a few places needed to be adjusted to support subscriptions. This is done and a test case is added. It is important to implement subscriptions now, because they require changes to the library API, and they are a big missing part to finish the executor. When the executor is finished, we can start to provide more stable API without breaking everything every release. Validation and introspection shouldn't require much changes to the API; AST would require some changes to report good errors after the validation - this is one thing I can think of. Fixes #5.
150 lines
3.7 KiB
Plaintext
150 lines
3.7 KiB
Plaintext
---
|
|
title: GraphQL Haskell Tutorial
|
|
---
|
|
|
|
|
|
== Getting started ==
|
|
|
|
Welcome to GraphQL!
|
|
|
|
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 #-}
|
|
> module Main where
|
|
>
|
|
> import Control.Monad.IO.Class (liftIO)
|
|
> import Data.Aeson (encode)
|
|
> import Data.ByteString.Lazy.Char8 (putStrLn)
|
|
> import qualified Data.HashMap.Strict as HashMap
|
|
> import Data.Text (Text)
|
|
> import qualified Data.Text as Text
|
|
> import Data.Time (getCurrentTime)
|
|
>
|
|
> import Language.GraphQL
|
|
> import Language.GraphQL.Type
|
|
> import qualified Language.GraphQL.Type.Out as Out
|
|
>
|
|
> import Prelude hiding (putStrLn)
|
|
|
|
|
|
=== 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 :: Schema IO
|
|
> schema1 = Schema
|
|
> { query = queryType , mutation = Nothing , subscription = Nothing }
|
|
>
|
|
> queryType :: ObjectType IO
|
|
> queryType = ObjectType "Query" Nothing []
|
|
> $ HashMap.singleton "hello"
|
|
> $ ValueResolver helloField hello
|
|
>
|
|
> helloField :: Field IO
|
|
> helloField = Field Nothing (Out.NamedScalarType string) mempty
|
|
>
|
|
> hello :: Resolve IO
|
|
> hello = pure $ String "it's me"
|
|
|
|
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 = graphql schema1 query1 >>= putStrLn . encode
|
|
|
|
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
|
|
> { query = queryType2, mutation = Nothing, subscription = Nothing }
|
|
>
|
|
> queryType2 :: ObjectType IO
|
|
> queryType2 = ObjectType "Query" Nothing []
|
|
> $ HashMap.singleton "time"
|
|
> $ ValueResolver timeField time
|
|
>
|
|
> timeField :: Field IO
|
|
> timeField = Field Nothing (Out.NamedScalarType string) mempty
|
|
>
|
|
> time :: Resolve IO
|
|
> time = do
|
|
> t <- liftIO getCurrentTime
|
|
> pure $ String $ Text.pack $ show t
|
|
|
|
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 = graphql schema2 query2 >>= putStrLn . encode
|
|
|
|
This runs the query, returning the current time
|
|
|
|
```{"data": {"time":"2016-03-08 23:28:14.546899 UTC"}}```
|
|
|
|
|
|
=== Combining resolvers ===
|
|
|
|
Now that we have two resolvers, we can define a schema which uses them both.
|
|
|
|
> schema3 :: Schema IO
|
|
> schema3 = Schema
|
|
> { query = queryType3, mutation = Nothing, subscription = Nothing }
|
|
>
|
|
> queryType3 :: ObjectType IO
|
|
> queryType3 = ObjectType "Query" Nothing [] $ HashMap.fromList
|
|
> [ ("hello", ValueResolver helloField hello)
|
|
> , ("time", ValueResolver timeField time)
|
|
> ]
|
|
>
|
|
> query3 :: Text
|
|
> query3 = "query timeAndHello { time hello }"
|
|
>
|
|
> main3 :: IO ()
|
|
> main3 = graphql schema3 query3 >>= putStrLn . encode
|
|
|
|
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.
|
|
|
|
> main :: IO ()
|
|
> main = main1 >> main2 >> main3
|