View Source GraphQLDocument (GraphQLDocument v0.2.0)

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]). See field/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: and select: 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

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]
  ]
}

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]
  ]
}
Link to this function

mutation(selections, opts \\ [])

View Source

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
  }
}\
"""

Creates a TypeCondition for a Fragment.

See GraphQLDocument.Fragment for more details.

example

Example

iex> on(User)
{:on, User}
Link to this function

query(selections, opts \\ [])

View Source

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
}\
"""
Link to this function

subscription(selections, opts \\ [])

View Source

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}