grafeo

A GraphQL document and schema language based on S-expressions in Clojure & ClojureScript

EPL-1.0 License

Downloads
2.5K
Stars
11
Committers
1
  • Grafeo

    #+author: r0man #+LANGUAGE: en

    [[https://clojars.org/grafeo][https://img.shields.io/clojars/v/grafeo.svg]] [[https://travis-ci.org/r0man/grafeo][https://travis-ci.org/r0man/grafeo.svg]] [[https://versions.deps.co/r0man/grafeo][https://versions.deps.co/r0man/grafeo/status.svg]] [[https://versions.deps.co/r0man/grafeo][https://versions.deps.co/r0man/grafeo/downloads.svg]]

    /Grafeo/ is [[https://clojure.org][Clojure]] and [[https://github.com/clojure/clojurescript][ClojureScript]] library that provides a S-expression based language for [[https://graphql.org/][GraphQL]] documents and schemas.

** Usage

Require the library.

#+BEGIN_SRC clojure :exports code :results silent (require '[clojure.pprint :refer [pprint]]) (require '[grafeo.core :as gql]) #+END_SRC

Define a GraphQL document in s-expression format. Take a look at the [[https://github.com/r0man/grafeo/tree/master/doc][doc]] folder to learn how to write GraphQL documents and schemas in S-expression format.

#+BEGIN_SRC clojure :exports code :results silent (def my-document '((human [(id "1000")] name (height [(unit FOOT)])))) #+END_SRC

*** Pretty printing

Pretty print the GraphQL document.

#+BEGIN_SRC clojure :exports both :results output
 (gql/pprint my-document)
#+END_SRC

#+RESULTS:
: query {
:   human(id: "1000") {
:     name
:     height(unit: FOOT)
:   }
: }

*** Alumbra

[[https://github.com/alumbra][Alumbra]] is a very complete GraphQL library for Clojure. It
provides an [[https://github.com/alumbra/alumbra.analyzer][analyzer]], a [[https://github.com/alumbra/alumbra.parser][parser]] and Clojure [[https://clojure.org/guides/spec][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
[[https://github.com/alumbra][Alumbra]] AST.

#+BEGIN_SRC clojure :exports both :results output
 (binding [*print-namespace-maps* false]
   (pprint (gql/parse-document my-document)))
#+END_SRC

#+RESULTS:
#+begin_example
{: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}}]}]}]}]}
#+end_example

*** JavaScript

In the JavaScript world, GraphQL clients like [[https://www.apollographql.com/docs/react/][Apollo]] and [[https://facebook.github.io/relay/][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.

#+BEGIN_SRC clojure :exports both :results output
 (pprint (gql/parse-document-js my-document))
#+END_SRC

#+RESULTS:
#+begin_example
{: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}}}
#+end_example

*** HTTP Client

/Grafeo/ provides a [[https://github.com/dakrone/clj-http][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][http://localhost:4000/graphql]].

#+BEGIN_SRC clojure :exports both :results silent
  node server.js
#+END_SRC

Require the HTTP client.

#+BEGIN_SRC clojure :exports both :results silent
  (require '[grafeo.http :as http])
#+END_SRC

Define the server we are talking to.

#+BEGIN_SRC clojure :exports both :results silent
  (def my-server
    {:scheme :http
     :server-name "localhost"
     :server-port 4000})
#+END_SRC

Query the local Star Wars API server and print the result.

#+BEGIN_SRC clojure :exports both :results output
  (->> (http/request my-server my-document) :body pprint)
#+END_SRC

#+RESULTS:
: {:data {:human {:name "Luke Skywalker", :height 5.6430448}}}

With variables.

#+BEGIN_SRC clojure :exports both :results output
  (->> (http/request
        my-server
        '((query
           HeroNameAndFriends
           [($episode Episode)]
           (hero
            [(episode $episode)]
            name
            (friends name))))
        {:variables {:episode "JEDI"}})
       :body pprint)
#+END_SRC

#+RESULTS:
: {:data
:  {:hero
:   {:name "R2-D2",
:    :friends
:    [{:name "Luke Skywalker"}
:     {:name "Han Solo"}
:     {:name "Leia Organa"}]}}}

** License

Copyright © 2019 [[https://github.com/r0man][r0man]]

Distributed under the Eclipse Public License, the same as Clojure.

Package Rankings
Top 24.63% on Clojars.org