A GraphQL toolkit providing the following:
- Alex Lexer of the
GraphQL
lexical specification. - Happy Parser of the
GraphQL
BNF Grammar. - Pretty printer of the
GraphQL
abstract syntax tree (AST) for human consumption. - QuickCheck generators for creating random AST fragments
- Used in conjunction with pretty printing to establish round trip property tests.
- Source
- Generics implementation providing correct-by-construction
Schema
at compile time. - QuasiQuoter providing inline definitions of
ExecutableDefinitions
.
{-# LANGUAGE QuasiQuotes #-}
module Main (main) where
import GraphQL.QQ (query)
main :: IO ()
main = print [query| { building (id: 123) {floorCount, id}} |]
QueryDocument {getDefinitions = [
DefinitionOperation (AnonymousQuery [
SelectionField (Field Nothing (Name {unName = "building"}) [
Argument (Name {unName = "id"}) (ValueInt 123)] [] [
SelectionField (Field Nothing (Name {unName = "floorCount"}) [] [] [])
, SelectionField (Field Nothing (Name {unName = "id"}) [] [] [])
])
])
]}
GraphQL ExecutableDefinition
abstract syntax tree rewriting is made possible via Template Haskell's metavariable substitution. During QuasiQuotation
all unbound variables in a GraphQL
query that have identical names inside the current scope will automatically be translated into GraphQL
AST terms and substituted.
buildingQuery
:: Int
-> ExecutableDefinition
buildingQuery buildingId =
[query| { building (id: $buildingId) {floorCount, id}} |]
QueryDocument {getDefinitions = [
DefinitionOperation (AnonymousQuery [
SelectionField (Field Nothing (Name {unName = "building"}) [
Argument (Name {unName = "buildingId"}) (ValueInt 4)] [] [
SelectionField (Field Nothing (Name {unName = "floorCount"}) [] [] [])
, SelectionField (Field Nothing (Name {unName = "id"}) [] [] [])
])
])
]}
It is possible to derive GraphQL schema using GHC.Generics
.
Simply import GHC.Generics
, derive Generic
(must enable the DeriveGeneric
language extension) and make an instance of ToObjectTypeDefintion
.
See below for an example:
{-# LANGUAGE DeriveGeneric #-}
module Main where
import GHC.Generics (Generic)
import GraphQL.Internal.Syntax.Encoder (schemaDocument)
import Data.Proxy (Proxy)
import qualified Data.Text.IO as T
import GraphQL.Generic (ToObjectTypeDefinition(..))
data Person = Person
{ name :: String
, age :: Int
} deriving (Show, Eq, Generic)
instance ToObjectTypeDefinition Person
showPersonSchema :: IO ()
showPersonSchema = print $ toObjectTypeDefinition (Proxy @ Person)
-- type Person{name:String!,age:Int!}
- Generic deriving is currently only supported on product types with record field selectors.
- Only
ObjectTypeDefintion
is currently supported.
- Generic deriving of
ScalarTypeDefintion
andEnumTypeDefintion
.
- Inspired by @edsko's work Quasi-quoting DSLs for free.
Alex
andHappy
lexing & parsing inspired by config-value
BSD3 2018-2019 Urbint Inc.