GraphQL SDL Parsing

As noted in the overview, Lacinia schemas are represented as Clojure data. However, Lacinia also contains a facility to transform schemas written in the GraphQL Schema Definition Language into the form usable by Lacinia. This is exposed by the function com.walmartlabs.lacinia.parser.schema/parse-schema.

The Lacinia schema definition includes things which are not available in the SDL, such as resolvers, subscription streamers, custom scalar parsers/serializers and documentation. To add these, parse-schema has two arguments: a string containing the SDL schema definition, and a map of resolvers, streamers, scalar functions and documentation to attach to the schema:

{:resolvers {:field-name resolver-fn}
 :streamers {:field-name stream-fn}
 :scalars {:scalar-name {:parse parse-spec
                         :serialize serialize-spec}}
 :documentation {:type-name doc-str
                 :type-name/field-name doc-str
                 :type-name/field-name.arg-name doc-str}}

Example

schema.txt
enum episode {
  NEWHOPE
  EMPIRE
  JEDI
}

type Character {
  name: String!
  episodes: [episode]
}

input CharacterArg {
  name: String!
  episodes: [episode]!
}

type Query {
  find_all_in_episode(episode: episode!) : [Character]
}

type Mutation {
  add_character(character: CharacterArg!) : Boolean
}

schema {
  query: Query
  mutation: Mutation
}
(parse-schema (slurp (clojure.java.io/resource "schema.txt"))
              {:resolvers {:Query {:find_all_in_episode :find-all-in-episode}
                                   :Mutation {:add_character :add-character}}
               :documentation {:Character "A Star Wars character"
                               :Character/name "Character name"
                               :Query/find_all_in_episode "Find all characters in the given episode"
                               :Query/find_all_in_episode.episode "Episode for which to find characters."}})
Return value of parse-schema
{:objects
 {:Character {:fields
              {:name {:type (non-null String)
                      :description "Character name"}
               :episodes {:type (list :episode)}}
              :description "A Star Wars character"}
  :Query {:fields
          {:find_all_in_episode {:type (list :Character)
                                 :args
                                 {:episode
                                  {:type (non-null :episode)
                                   :description "Episode for which to find characters."}}
                                 :resolve :find-all-in-episode
                                 :description "Find all characters in the given episode"}}}
  :Mutation {:fields
             {:add_character
              {:type Boolean
               :args {:character {:type (non-null :CharacterArg)}}
               :resolve :add-character}}}}

 :input-objects
 {:CharacterArg {:fields
                 {:name {:type (non-null String)}
                  :episodes {:type (non-null (list :episode))}}}}

 :enums
 {:episode {:values [{:enum-value :NEWHOPE}
                     {:enum-value :EMPIRE}
                     {:enum-value :JEDI}]}}

 :roots
 {:query :Query
  :mutation :Mutation}}

The :documentation key uses a naming convention on the keys which become paths into the Lacinia input schema. :Character/name applies to the name field of the Character object. :Query/find_all_in_episode.episode applies to the episode argument, inside the find_all_in_episode field of the Query object.

Tip

Attaching documentation this way is less necessary since release 0.29.0, which added support for embedded schema documentation.

Alternately, the documentation map can be parsed from a Markdown file using com.walmartlabs.lacinia.parser.docs/parse-docs.

The same key structure can be used to document input objects and interfaces.

Unions may be documented, but do not contain fields.

Enums may be documented, as well as Enum values (e.g., :Episode/JEDI).

As is normal with Schema Definition Language, the available queries, mutations, and subscriptions (not shown in this example) are defined on ordinary schema objects, and the schema element identifies which objects are used for which purposes.

The :roots map inside the Lacinia schema is equivalent to the schema element in the SDL.

Warning

Schema extensions are defined in the GraphQL specification, but not yet implemented.