summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2020-11-02 08:24:48 +0100
committerEugen Wissner <belka@caraus.de>2020-11-02 08:24:48 +0100
commitafcf9aaa14e925ca137ec956e3bfd47d2506c904 (patch)
treeb108a19882c9057dc7c7ad9166c58b05ed08bd80
parent6e8d8a34a1ce07b8d9cd10d8e5c3e009d17cfdf7 (diff)
downloadgraphql-afcf9aaa14e925ca137ec956e3bfd47d2506c904.tar.gz
Write documentation out of the source tree
In a Wiki.
-rw-r--r--CONTRIBUTING.md31
-rw-r--r--README.md103
-rw-r--r--docs/tutorial/test.hs55
-rw-r--r--docs/tutorial/tutorial.lhs149
-rw-r--r--graphql.cabal4
-rw-r--r--package.yaml2
6 files changed, 4 insertions, 340 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index a1441f5..0000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# Contributing guidelines
-
-## Testing
-
-To ensure all code changes adhere to existing code quality standards, some
-automatic checks can be run locally.
-
-Ensure that the code builds without warnings and passes the tests:
-
-```sh
-stack test --pedantic
-```
-
-And also run the linter on your code:
-
-```sh
-stack build hlint
-stack exec hlint -- src tests
-```
-
-Build the documentation and check if you get any warnings:
-
-```sh
-stack haddock
-```
-
-Validate that literate Haskell (tutorials) files compile without any warnings:
-
-```sh
-stack ghc -- -Wall -fno-code docs/tutorial/*.lhs
-```
diff --git a/README.md b/README.md
index 74c0ee3..aa83027 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,8 @@
# GraphQL implementation in Haskell
+[![Simple Haskell](https://www.simplehaskell.org/badges/badge.svg)](https://www.simplehaskell.org)
+[![CI/CD](https://img.shields.io/badge/CI-CD-brightgreen)](https://build.caraus.tech/go/pipelines)
+
This implementation is relatively low-level by design, it doesn't provide any
mappings between the GraphQL types and Haskell's type system and avoids
compile-time magic. It focuses on flexibility instead, so other solutions can
@@ -29,103 +32,3 @@ API documentation is available through
Further documentation will be made available in the
[Wiki](https://www.caraus.tech/projects/pub-graphql/wiki).
-
-### Getting started
-
-We start with a simple GraphQL API that provides us with some famous and less
-famous cites.
-
-```graphql
-"""
-Root Query type.
-"""
-type Query {
- """
- Provides a cite.
- """
- cite: String!
-}
-```
-
-This is called a GraphQL schema, it defines all queries supported by the API.
-`Query` is the root query type. Every GraphQL API should define a query type.
-
-`Query` has a single field `cite` that returns a `String`. The `!` after the
-type denotes that the returned value cannot be `Null`. GraphQL fields are
-nullable by default.
-
-To be able to work with this schema, we are going to implement it in Haskell.
-
-```haskell
-{-# LANGUAGE OverloadedStrings #-}
-
-import qualified Data.Aeson as Aeson
-import qualified Data.ByteString.Lazy.Char8 as ByteString.Lazy.Char8
-import qualified Data.HashMap.Strict as HashMap
-import Language.GraphQL
-import Language.GraphQL.Type
-import qualified Language.GraphQL.Type.Out as Out
-
--- GraphQL supports 3 kinds of operations: queries, mutations and subscriptions.
--- Our first schema supports only queries.
-citeSchema :: Schema IO
-citeSchema = schema queryType Nothing Nothing mempty
-
--- GraphQL distinguishes between input and output types. Input types are field
--- argument types and they are defined in Language.GraphQL.Type.In. Output types
--- are result types, they are defined in Language.GraphQL.Type.Out. Root types
--- are always object types.
---
--- Here we define a type "Query". The second argument is an optional
--- description, the third one is the list of interfaces implemented by the
--- object type. The last argument is a field map. Keys are field names, values
--- are field definitions and resolvers. Resolvers are the functions, where the
--- actual logic lives, they return values for the respective fields.
-queryType :: Out.ObjectType IO
-queryType = Out.ObjectType "Query" (Just "Root Query type.") []
- $ HashMap.singleton "cite" citeResolver
- where
- -- 'ValueResolver' is a 'Resolver' data constructor, it combines a field
- -- definition with its resolver function. This function resolves a value for
- -- a field (as opposed to the 'EventStreamResolver' used by subscriptions).
- -- Our resolver just returns a constant value.
- citeResolver = ValueResolver citeField
- $ pure "Piscis primum a capite foetat"
-
- -- The first argument is an optional field description. The second one is
- -- the field type and the third one is for arguments (we have none in this
- -- example).
- --
- -- GraphQL has named and wrapping types. String is a scalar, named type.
- -- Named types are nullable by default. To make our "cite" field
- -- non-nullable, we wrap it in the wrapping type, Non-Null.
- citeField = Out.Field
- (Just "Provides a cite.") (Out.NonNullScalarType string) HashMap.empty
-
--- Now we can execute a query. Since our schema defines only one field,
--- everything we can do is to ask to resolve it and give back the result.
--- Since subscriptions don't return plain values, the 'graphql' function returns
--- an 'Either'. 'Left' is for subscriptions, 'Right' is for queries and
--- mutations.
-main :: IO ()
-main = do
- Right result <- graphql citeSchema "{ cite }"
- ByteString.Lazy.Char8.putStrLn $ Aeson.encode result
-```
-
-Executing this query produces the following JSON:
-
-```json
-{
- "data": {
- "cite": "Piscis primum a capite foetat"
- }
-}
-```
-
-## Contact
-
-Suggestions, patches and bug reports are welcome.
-
-Should you have questions on usage, please open an issue and ask – this helps
-to write useful documentation.
diff --git a/docs/tutorial/test.hs b/docs/tutorial/test.hs
deleted file mode 100644
index 631407c..0000000
--- a/docs/tutorial/test.hs
+++ /dev/null
@@ -1,55 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-import qualified Data.Aeson as Aeson
-import qualified Data.ByteString.Lazy.Char8 as ByteString.Lazy.Char8
-import qualified Data.HashMap.Strict as HashMap
-import Language.GraphQL
-import Language.GraphQL.Type
-import qualified Language.GraphQL.Type.Out as Out
-
--- GraphQL supports 3 kinds of operations: queries, mutations and subscriptions.
--- Our first schema supports only queries.
-citeSchema :: Schema IO
-citeSchema = schema queryType
-
--- GraphQL distinguishes between input and output types. Input types are field
--- argument types and they are defined in Language.GraphQL.Type.In. Output types
--- are result types, they are defined in Language.GraphQL.Type.Out. Root types
--- are always object types.
---
--- Here we define a type "Query". The second argument is an optional
--- description, the third one is the list of interfaces implemented by the
--- object type. The last argument is a field map. Keys are field names, values
--- are field definitions and resolvers. Resolvers are the functions, where the
--- actual logic lives, they return values for the respective fields.
-queryType :: Out.ObjectType IO
-queryType = Out.ObjectType "Query" (Just "Root Query type.") []
- $ HashMap.singleton "cite" citeResolver
- where
- -- 'ValueResolver' is a 'Resolver' data constructor, it combines a field
- -- definition with its resolver function. This function resolves a value for
- -- a field (as opposed to the 'EventStreamResolver' used by subscriptions).
- -- Our resolver just returns a constant value.
- citeResolver = ValueResolver citeField
- $ pure "Piscis primum a capite foetat"
-
- -- The first argument is an optional field description. The second one is
- -- the field type and the third one is for arguments (we have none in this
- -- example).
- --
- -- GraphQL has named and wrapping types. String is a scalar, named type.
- -- Named types are nullable by default. To make our "cite" field
- -- non-nullable, we wrap it in the wrapping type, Non-Null.
- citeField = Out.Field
- (Just "Provides a cite.") (Out.NonNullScalarType string) HashMap.empty
-
--- Now we can execute a query. Since our schema defines only one field,
--- everything we can do is to ask to resolve it and give back the result.
--- Since subscriptions don't return plain values, the 'graphql' function returns
--- an 'Either'. 'Left' is for subscriptions, 'Right' is for queries and
--- mutations.
-main :: IO ()
-main = do
- Right result <- graphql citeSchema "{ cite }"
- ByteString.Lazy.Char8.putStrLn $ Aeson.encode result
-
diff --git a/docs/tutorial/tutorial.lhs b/docs/tutorial/tutorial.lhs
deleted file mode 100644
index 1024251..0000000
--- a/docs/tutorial/tutorial.lhs
+++ /dev/null
@@ -1,149 +0,0 @@
----
-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 queryType Nothing Nothing mempty
->
-> 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
-> >>= either (const $ pure ()) (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 queryType2 Nothing Nothing mempty
->
-> 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
-> >>= either (const $ pure ()) (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 queryType3 Nothing Nothing mempty
->
-> 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
-> >>= either (const $ pure ()) (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
diff --git a/graphql.cabal b/graphql.cabal
index bdd7532..337e397 100644
--- a/graphql.cabal
+++ b/graphql.cabal
@@ -4,7 +4,7 @@ cabal-version: 2.2
--
-- see: https://github.com/sol/hpack
--
--- hash: 64b8d806f87030d33d1f8d505887d4913689ee48bc6e79b1c24b5226ffd07ee8
+-- hash: ddb79ddbd13b917f320fff372b4a29b63b6eb0ed113ca732c1d779b4e6a296d8
name: graphql
version: 0.10.0.0
@@ -25,9 +25,7 @@ license-files: LICENSE,
build-type: Simple
extra-source-files:
CHANGELOG.md
- CONTRIBUTING.md
README.md
- docs/tutorial/tutorial.lhs
source-repository head
type: git
diff --git a/package.yaml b/package.yaml
index 3e84a76..b050492 100644
--- a/package.yaml
+++ b/package.yaml
@@ -23,9 +23,7 @@ license-file:
- LICENSE.MPL
extra-source-files:
- CHANGELOG.md
-- CONTRIBUTING.md
- README.md
-- docs/tutorial/tutorial.lhs
dependencies:
- aeson