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¶
enum episode {
NEWHOPE
EMPIRE
JEDI
}
type Character {
name: String!
episodes: [episode]
}
input CharacterArg {
name: String!
episodes: [episode]!
}
type Query {
findAllInEpisode(episode: episode!) : [Character]
}
type Mutation {
addCharacter(character: CharacterArg!) : Boolean
}
(parse-schema (slurp (clojure.java.io/resource "schema.txt"))
{:resolvers {:Query/findAllInEpsiode :find-all-in-episode
:Mutation/addCharacter :add-character}}
:documentation {:Character "A Star Wars character"
:Character/name "Character name"
:Query/findAllInEpisode "Find all characters in the given episode"
:Query/findAllInEpisode.episode "Episode for which to find characters."}})
{:objects
{:Character {:fields
{:name {:type (non-null String)
:description "Character name"}
:episodes {:type (list :episode)}}
:description "A Star Wars character"}
:Query {:fields
{:findAllInEpisode
{: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
{:addCharacter
{: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.