metosin / oksa

Generate GraphQL queries using Clojure data structures.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

oksa

Generate GraphQL queries using Clojure data structures.

Project status

Clojars Project Slack cljdoc badge

Oksa is currently experimental.

Usage

(require '[oksa.core :as oksa])
(oksa/unparse [:hello [:world]])
;; => "{hello{world}}"

Operation definitions

Selection sets

Fields can be selected:

(oksa/unparse [:foo])
;; => "{foo}"

(oksa/unparse [:foo :bar])
;; => "{foo bar}"

(oksa/unparse [:bar [:qux [:baz]]])
;; => "{bar{qux{baz}}}"

(oksa/unparse [:foo :bar [:qux [:baz]]])
;; => "{foo bar{qux{baz}}}"

(oksa/unparse [:foo :bar [:qux :baz]])
;; => "{foo bar{qux baz}}"

(oksa/unparse [:foo [:bar [:baz :qux] :frob]])
;; => "{foo{bar{baz qux} frob}}"

Strings are supported for field names:

(oksa/unparse ["query" "foo"])
;; => "{query foo}"

Aliases:

(oksa/unparse [[:foo {:alias :bar}]])
;; => "{bar:foo}"

Arguments:

(oksa/unparse [[:foo {:arguments {:a 1
                                  :b "hello world"
                                  :c true
                                  :d nil
                                  :e :foo
                                  :f [1 2 3]
                                  :g {:frob {:foo 1
                                             :bar 2}}
                                  :h :$fooVar}}]])
;; => "{foo(a:1, b:\"hello world\", c:true, d:null, e:foo, f:[1 2 3], g:{frob:{foo:1, bar:2}}, h:$fooVar)}"

Directives:

(oksa/unparse [[:foo {:directives [:bar]}]])
;; => "{foo@bar}"

;; with arguments
(oksa/unparse [[:foo {:directives [[:bar {:arguments {:qux 123}}]]}]])
;; => "{foo@bar(qux:123)}"

Queries

Queries can be created:

(oksa/unparse [:oksa/query [:foo :bar [:qux [:baz]]]])
;; => "query {foo bar{qux{baz}}}"

(oksa/unparse [:oksa/query {:name :Foo} [:foo]])
;; => "query Foo {foo}"

Queries can have directives:

(oksa/unparse [:oksa/query {:directives [:foo]} [:foo]])
;; => "query @foo{foo}"

(oksa/unparse [:oksa/query {:directives [:foo :bar]} [:foo]])
;; => "query @foo @bar{foo}"

;; with arguments

(oksa/unparse [:oksa/query {:directives [[:foo {:arguments {:bar 123}}]]} [:foo]])
;; => "query @foo(bar:123){foo}"

Mutations

Mutations can be created:

(oksa/unparse [:oksa/mutation [:foo :bar [:qux [:baz]]]])
;; => "mutation {foo bar{qux{baz}}}"

(oksa/unparse [:oksa/mutation {:name :Foo} [:foo]])
;; => "mutation Foo {foo}"

Subscriptions

Subscriptions can be created:

(oksa/unparse [:oksa/subscription [:foo :bar [:qux [:baz]]]])
;; => "subscription {foo bar{qux{baz}}}"

(oksa/unparse [:oksa/subscription {:name :Foo} [:foo]])
;; => "subscription Foo {foo}"

Variable definitions

Named types are supported:

(oksa/unparse [:oksa/query {:variables [:fooVar :FooType]}
               [:fooField]])
;; => "query ($fooVar:FooType){fooField}"

(oksa/unparse [:oksa/query {:variables
                            [:fooVar :FooType
                             :barVar :BarType]}
               [:fooField]])
;; => "query ($fooVar:FooType,$barVar:BarType){fooField}"

Lists can be created:

(oksa/unparse [:oksa/query {:variables
                            [:fooVar [:oksa/list :FooType]]}
               [:fooField]])

;; or

(oksa/unparse [:oksa/query {:variables
                            [:fooVar [:FooType]]}
               [:fooField]])
;; => "query ($fooVar:[FooType]){fooField}"

(oksa/unparse [:oksa/query {:variables
                            [:fooVar [:oksa/list
                                      [:oksa/list
                                       :BarType]]]}
               [:fooField]])

;; or

(oksa/unparse [:oksa/query {:variables [:fooVar [[:BarType]]]}
               [:fooField]])
;; => "query ($fooVar:[[BarType]]){fooField}"

Non-null types can be created:

(oksa/unparse [:oksa/query {:variables
                            [:fooVar [:FooType {:non-null true}]]}
               [:fooField]])

;; or

(oksa/unparse [:oksa/query {:variables [:fooVar :FooType!]}
               [:fooField]])
;; => "query ($fooVar:FooType!){fooField}"

(oksa/unparse [:oksa/query {:variables
                            [:fooVar [:oksa/list {:non-null true}
                                      :BarType]]}
               [:fooField]])

;; or

(oksa/unparse [:oksa/query {:variables [:fooVar [:! :BarType]]}
               [:fooField]])
;; => "query ($fooVar:[BarType]!){fooField}"

Getting crazy with it:

(oksa/unparse [:oksa/query {:variables [:fooVar [:! [:! :BarType!]]]}
               [:fooField]])
;; => "query ($fooVar:[[BarType!]!]!){fooField}"

Variable definitions can have directives:

(oksa/unparse [:oksa/query {:variables [:foo {:directives [:fooDirective]} :Bar]}
               [:fooField]])
;; => "query ($foo:Bar @fooDirective){fooField}"

(oksa/unparse [:oksa/query {:variables [:foo {:directives [[:fooDirective {:arguments {:fooArg 123}}]]} :Bar]}
               [:fooField]])
;; => "query ($foo:Bar @fooDirective(fooArg:123)){fooField}"

Fragments

Fragment definitions can be created:

(oksa/unparse [:oksa/fragment {:name :Foo :on :Bar} [:foo]])
;; => "fragment Foo on Bar{foo}"

(oksa/unparse [:# {:name :Foo :on :Bar} [:foo]]) ; shortcut
;; => "fragment Foo on Bar{foo}"

;; with directives
(oksa/unparse [:oksa/fragment {:name :foo
                               :on :Foo
                               :directives [:fooDirective]}
               [:bar]])
;; => "fragment foo on Foo@fooDirective{bar}"

;; with arguments
(oksa/unparse [:oksa/fragment {:name :foo
                               :on :Foo
                               :directives [[:fooDirective {:arguments {:bar 123}}]]}
               [:bar]])
;; => "fragment foo on Foo@fooDirective(bar:123){bar}"

Fragment spreads:

(oksa/unparse [:foo [:oksa/fragment-spread {:name :bar}]])

;; or

(oksa/unparse [:foo [:... {:name :bar}]])
;; => "{foo ...bar}"

;; with directives
(oksa/unparse [[:... {:name :foo :directives [:bar]}]])
;; => "{...foo@bar}"

;; with arguments
(oksa/unparse [[:... {:name :foo
                      :directives [[:bar {:arguments {:qux 123}}]]}]])
;; => "{...foo@bar(qux:123)}"

Inline fragments:

(oksa/unparse [:foo [:oksa/inline-fragment [:bar]]])

;; or

(oksa/unparse [:foo [:... [:bar]]])
;; => "{foo ...{bar}}"

(oksa/unparse [:foo [:... {:on :Bar} [:bar]]])
;; => "{foo ...on Bar{bar}}"

;; with directives
(oksa/unparse [[:... {:directives [:foo]} [:bar]]])
;; => "{...@foo{bar}}"

;; with arguments
(oksa/unparse [[:... {:directives [[:foo {:arguments {:bar 123}}]]}
                [:foobar]]])
;; => "{...@foo(bar:123){foobar}}"

Document

Putting it all together:

(oksa/unparse [:oksa/document
               [:foo]
               [:oksa/query [:bar]]
               [:oksa/mutation [:qux]]
               [:oksa/subscription [:baz]]
               [:oksa/fragment {:name :foo :on :Foo} [:bar]]])
;; => "{foo}\nquery {bar}\nmutation {qux}\nsubscription {baz}\nfragment foo on Foo{bar}"

(oksa/unparse [:<> [:foo] [:bar]]) ; :<> also supported
;; => "{foo}\n{bar}"

Rationale

There are some awesome GraphQL query generation libraries out there, notably:

With oksa we want to provide:

  • A platform-agnostic library meant for purely building GraphQL queries.
  • Support for the entire syntax under ExecutableDefinition plus some parts from Document for added composability of queries.
  • A data-driven library with a malli-like syntax.

About

Generate GraphQL queries using Clojure data structures.

License:Eclipse Public License 2.0


Languages

Language:Clojure 99.6%Language:Shell 0.4%