A GraphQL toolkit providing the following:
- Alex Lexer of the
GraphQLlexical specification. - Happy Parser of the
GraphQLBNF Grammar. - Pretty printer of the
GraphQLabstract 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
Schemaat 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
ObjectTypeDefintionis currently supported.
- Generic deriving of
ScalarTypeDefintionandEnumTypeDefintion.
- Inspired by @edsko's work Quasi-quoting DSLs for free.
AlexandHappylexing & parsing inspired by config-value
BSD3 2018-2019 Urbint Inc.