Grafeo is Clojure and ClojureScript library that provides a S-expression based language for GraphQL documents and schemas.
Require the library.
(require '[clojure.pprint :refer [pprint]])
(require '[grafeo.core :as gql])Define a GraphQL document in s-expression format. Take a look at the doc folder to learn how to write GraphQL documents and schemas in S-expression format.
(def my-document
'((human
[(id "1000")]
name
(height [(unit FOOT)]))))Pretty print the GraphQL document.
(gql/pprint my-document)query {
human(id: "1000") {
name
height(unit: FOOT)
}
}
Alumbra is a very complete GraphQL library for Clojure. It provides an analyzer, a parser and Clojure Specs around GraphQL. When parsing a Grafeo GraphQL document in S-expressions format it is converted into Alumbra’s AST format.
The following example parses the GraphQL document and prints the Alumbra AST.
(binding [*print-namespace-maps* false]
(pprint (gql/parse-document my-document))){:alumbra/metadata {:column 0, :row 0},
:alumbra/operations
[{:alumbra/metadata {:column 0, :row 0},
:alumbra/operation-type "query",
:alumbra/selection-set
[{:alumbra/field-name "human",
:alumbra/metadata {:column 0, :row 0},
:alumbra/arguments
[{:alumbra/argument-name "id",
:alumbra/argument-value
{:alumbra/metadata {:column 0, :row 0},
:alumbra/string "1000",
:alumbra/value-type :string},
:alumbra/metadata {:column 0, :row 0}}],
:alumbra/selection-set
[{:alumbra/field-name "name",
:alumbra/metadata {:column 0, :row 0}}
{:alumbra/field-name "height",
:alumbra/metadata {:column 0, :row 0},
:alumbra/arguments
[{:alumbra/argument-name "unit",
:alumbra/argument-value
{:alumbra/enum "FOOT",
:alumbra/metadata {:column 0, :row 0},
:alumbra/value-type :enum},
:alumbra/metadata {:column 0, :row 0}}]}]}]}]}
In the JavaScript world, GraphQL clients like Apollo and Relay use a different AST format. Grafeo can translate between the Alumbra and JavaScript formats.
The following example parses the GraphQL document and prints the JavaScript AST.
(pprint (gql/parse-document-js my-document)){:definitions
[{:directives [],
:kind "OperationDefinition",
:loc {:startToken {:column 0, :line 0, :start nil}},
:name nil,
:operation "query",
:selectionSet
{:kind "SelectionSet",
:selections
[{:alias nil,
:arguments
[{:kind "Argument",
:loc {:startToken {:column 0, :line 0, :start nil}},
:name
{:kind "Name",
:loc {:startToken {:column 0, :line 0, :start nil}},
:value "id"},
:value
{:block false,
:kind "StringValue",
:loc {:startToken {:column 0, :line 0, :start nil}},
:value "1000"}}],
:directives [],
:kind "Field",
:loc {:startToken {:column 0, :line 0, :start nil}},
:name
{:kind "Name",
:loc {:startToken {:column 0, :line 0, :start nil}},
:value "human"},
:selectionSet
{:kind "SelectionSet",
:selections
[{:alias nil,
:arguments [],
:directives [],
:kind "Field",
:loc {:startToken {:column 0, :line 0, :start nil}},
:name
{:kind "Name",
:loc {:startToken {:column 0, :line 0, :start nil}},
:value "name"},
:selectionSet nil}
{:alias nil,
:arguments
[{:kind "Argument",
:loc {:startToken {:column 0, :line 0, :start nil}},
:name
{:kind "Name",
:loc {:startToken {:column 0, :line 0, :start nil}},
:value "unit"},
:value
{:kind "EnumValue",
:loc {:startToken {:column 0, :line 0, :start nil}},
:value "FOOT"}}],
:directives [],
:kind "Field",
:loc {:startToken {:column 0, :line 0, :start nil}},
:name
{:kind "Name",
:loc {:startToken {:column 0, :line 0, :start nil}},
:value "height"},
:selectionSet nil}]}}]},
:variableDefinitions []}],
:kind "Document",
:loc {:startToken {:column 0, :line 0, :start nil}}}
Grafeo provides a clj-http based HTTP client for GraphQL. The following example show how to query a GraphQL based server. Start the SWAPI server in this repository on http://localhost:4000/graphql.
node server.jsRequire the HTTP client.
(require '[grafeo.http :as http])Define the server we are talking to.
(def my-server
{:scheme :http
:server-name "localhost"
:server-port 4000})Query the local Star Wars API server and print the result.
(->> (http/request my-server my-document) :body pprint){:data {:human {:name "Luke Skywalker", :height 5.6430448}}}
With variables.
(->> (http/request
my-server
'((query
HeroNameAndFriends
[($episode Episode)]
(hero
[(episode $episode)]
name
(friends name))))
{:variables {:episode "JEDI"}})
:body pprint){:data
{:hero
{:name "R2-D2",
:friends
[{:name "Luke Skywalker"}
{:name "Han Solo"}
{:name "Leia Organa"}]}}}
Copyright © 2019 r0man
Distributed under the Eclipse Public License, the same as Clojure.