View Source GraphQLDocument (GraphQLDocument v0.2.2)
Builds GraphQL Documents from simple Elixir data structures.
These functions take Elixir data in the same structure as GraphQL and return the analogous GraphQL Document as a String
.
Using these abilities, developers can generate GraphQL queries programmatically.
GraphQLDocument
can be used to create higher-level
DSLs
for writing GraphQL queries.
getting-started
Getting Started
Elixir & GraphQL Code Snippets
Each Elixir code snippet is immediately followed by the GraphQL that it will produce.
All functions called in the code snippets below are in GraphQLDocument
.
(import GraphQLDocument
to directly use them.)
object-fields
Object Fields
To request a list of fields in an object, include them in a list.
query([
human: [
:name,
:height
]
])
query {
human {
name
height
}
}
arguments
Arguments
Wrap arguments along with child fields in a tuple.
{args, fields}
query(
human: {[id: "1000"], [
:name,
:height
]}
)
query {
human(id: "1000") {
name
height
}
}
Argument types and Enums
Elixir primitives (numbers, strings, lists, booleans, etc.) are translated into the analogous GraphQL primitive.
Enums are expressed with atoms, like MY_ENUM
, :MY_ENUM
, or :"MY_ENUM"
query(
human: {[id: "1000"], [
:name,
height: {[unit: FOOT], []}
]}
)
query {
human(id: "1000") {
name
height(unit: FOOT)
}
}
Expressing Arguments Without Sub-fields
Notice the slightly complicated syntax above:
height: {[unit: FOOT], []}
Since
args
can be expressed in{args, fields}
tuple, we put[]
where the sub-fields go because there are no sub-fields.This can also be expressed as
height: field(args: [unit: FOOT])
. Seefield/1
.
mixing-lists-and-keyword-lists
Mixing Lists and Keyword Lists
Since GraphQL supports a theoretically infinite amount of nesting, you can also nest as much as needed in the Elixir structure.
Furthermore, we can take advantage of Elixir's syntax feature that allows a regular list to be "mixed" with a keyword list. (The keyword pairs must be at the end.)
# Elixir allows lists with a Keyword List as the final members
[
:name,
:height,
friends: [
:name,
:age
]
]
Using this syntax, we can build a nested structure where we select primitive
fields (like :name
below) alongside object fields (like :friends
).
query(
human: {[id: "1000"], [
:name,
:height,
friends: {[olderThan: 30], [
:name,
:height
]}
]}
)
query {
human(id: "1000") {
name
height
friends(olderThan: 30) {
name
height
}
}
}
variables
Variables
To express a variable as a value, use {:var, var_name}
syntax or the
var/1
function.
The variable definition is passed as an option to query/2
, mutation/2
, or
subscription/2
.
Variable types can take the form Int
, {Int, null: false}
, or {Int, default: 1}
.
query(
[
user: {
[id: var(:myId)],
[
:name,
friends: {
[type: {:var, :friendType}],
[:name]
}
]
}
],
variables: [
myId: {Int, null: false},
friendType: {String, default: "best"}
]
)
query ($myId: Int!, $friendType: String = "best") {
user(id: $myId) {
name
friends(type: $friendType) {
name
}
}
}
fragments
Fragments
To express a fragment, use the :...
atom as the field name, similar to how
you would in GraphQL.
The fragment definition is passed as an option to query/2
, mutation/2
, or
subscription/2
.
Inline fragments and fragment definitions use the on/1
function to specify
the type condition.
query(
[
self: [
...: {
on(User),
[skip: [if: true]],
[:password, :passwordHash]
},
friends: [
...: :friendFields
]
]
],
fragments: [
friendFields: {on(User), [
:id,
:name,
profilePic: field(args: [size: 50])
]}
]
)
query {
self {
... on User @skip(if: true) {
password
passwordHash
}
friends(first: 10) {
...friendFields
}
}
}
fragment friendFields on User {
id
name
profilePic(size: 50)
}
features-that-require-field
Features That Require field()
The field/1
and field/2
functions are required in order to express Aliases
and Directives.
aliases
Aliases
Express an alias by putting the alias in place of the field name, and pass
the field name as the first argument to field/2
.
In the example below, me
is the alias and user
is the field.
Spot the Keyword List
args:
andselect:
below are members of an "invisible" keyword list using Elixir's call syntax.
query(
me: field(
:user,
args: [id: 100],
select: [:name, :email]
)
)
query {
me: user(id: 100) {
name
email
}
}
directives
Directives
Express a directive by passing directives:
to field/1
or field/2
.
A directive can be a single name (as an atom or string) or a tuple in
{name, args}
format.
query(
self: field(
directives: [:debug, log: [level: "warn"]]
select: [:name, :email]
)
)
query {
self @debug @log(level: "warn") {
name
email
}
}
not-yet-supported-features
Not-yet-supported features
GraphQLDocument
does not currently have the ability to generate Type System
definitions, although they technically belong in a Document.
Link to this section Summary
Functions
If you want to express a field with directives or an alias, you must use this function.
If you want to express a field with an alias, you must use this function.
Generate a GraphQL mutation document.
Creates a TypeCondition for a Fragment.
Generate a GraphQL query document.
Generate a GraphQL subscription document.
Wraps a variable name in a GraphQLDocument
-friendly tuple.
Link to this section Types
@type field_config() :: [ args: [Argument.t()], directives: [Directive.t()], select: [GraphQLDocument.Selection.t()] ]
Link to this section Functions
@spec field(field_config()) :: GraphQLDocument.Field.spec()
If you want to express a field with directives or an alias, you must use this function.
See field/2
if you want to specify an alias.
examples
Examples
iex> field(
...> args: [id: 2],
...> directives: [:debug],
...> select: [:name]
...> )
{
:field,
[
args: [id: 2],
directives: [:debug],
select: [:name]
]
}
@spec field(GraphQLDocument.Name.t(), field_config()) :: GraphQLDocument.Field.spec()
If you want to express a field with an alias, you must use this function.
Put the alias where you would normally put the field name, and pass the
field name as the first argument to field/2
.
See field/1
if you want to specify directives without an alias.
examples
Examples
iex> field(
...> :user,
...> args: [id: 2],
...> directives: [:debug],
...> select: [:name]
...> )
{
:field,
:user,
[
args: [id: 2],
directives: [:debug],
select: [:name]
]
}
@spec mutation([GraphQLDocument.Selection.t()], [GraphQLDocument.Operation.option()]) :: String.t()
Generate a GraphQL mutation document.
See the Getting Started section for more details.
example
Example
iex> mutation(
...> registerUser: {
...> [
...> name: "Ben",
...> hexUsername: "benwilson512",
...> packages: ["absinthe", "ex_aws"]
...> ],
...> [
...> :id,
...> ]
...> }
...> )
"""
mutation {
registerUser(name: "Ben", hexUsername: "benwilson512", packages: ["absinthe", "ex_aws"]) {
id
}
}\
"""
@spec on(GraphQLDocument.Name.t()) :: GraphQLDocument.Fragment.type_condition()
Creates a TypeCondition for a Fragment.
See GraphQLDocument.Fragment
for more details.
example
Example
iex> on(User)
{:on, User}
@spec query([GraphQLDocument.Selection.t()], [GraphQLDocument.Operation.option()]) :: String.t()
Generate a GraphQL query document.
See the Getting Started section for more details.
example
Example
iex> query(
...> [
...> customer: {[id: var(:customerId)], [
...> :name,
...> :email,
...> phoneNumbers: field(args: [type: MOBILE]),
...> cartItems: [
...> :costPerItem,
...> ...: :cartDetails
...> ]
...> ]}
...> ],
...> variables: [customerId: Int],
...> fragments: [cartDetails: {
...> on(CartItem),
...> [:sku, :description, :count]
...> }]
...> )
"""
query ($customerId: Int) {
customer(id: $customerId) {
name
email
phoneNumbers(type: MOBILE)
cartItems {
costPerItem
...cartDetails
}
}
}
\nfragment cartDetails on CartItem {
sku
description
count
}\
"""
@spec subscription([GraphQLDocument.Selection.t()], [ GraphQLDocument.Operation.option() ]) :: String.t()
Generate a GraphQL subscription document.
Works like query/2
and mutation/2
, except that it generates a
subscription.
See the Getting Started section for more details.
Wraps a variable name in a GraphQLDocument
-friendly tuple.
example
Example
iex> var(:foo)
{:var, :foo}