TypedGql.Macros (TypedGql v0.13.0)

Copy Markdown View Source

The macros a client module gets from use TypedGql.

defgql/2 and defgqlp/2 define a query function from a GraphQL document, and deffragment/1 registers a fragment those documents can spread. All three run at compile time: the document is parsed, validated against the loaded schema, and lowered into embedded schemas for its result and its variables, so a query the schema rejects fails the build rather than a call.

~GQL does none of that. It marks a string as GraphQL so mix format can format it and returns that string unchanged; the macro it is passed to is what compiles it.

Summary

Functions

Defines a reusable named GraphQL fragment.

Defines a public GraphQL query function.

Defines a private GraphQL query function.

A sigil for writing GraphQL query strings that can be formatted by mix format.

Functions

deffragment(fragment_string)

(macro)

Defines a reusable named GraphQL fragment.

At compile time, parses and validates the fragment against the schema, then registers it in the module for use by defgql/defgqlp. When a query uses ...FragmentName, the fragment definition is automatically appended to the query string sent to the server.

The fragment name is inferred from the GraphQL definition itself (fragment UserFields on User { ... }), so no separate Elixir name is required.

Fragments are resolved lexically: a defgql sees only the fragments defined before it in the module body. If the same fragment name is defined multiple times before a defgql, the latest definition wins. The same rule applies inside a fragment body: it may only spread fragments defined above it, and spreading one defined later is a compile error.

The ordering restriction comes from the macro model, not from GraphQL — the spec allows a spread to reference a fragment defined later in the same document. Each deffragment compiles as it is expanded, when later definitions do not exist yet, and lexical order is also what gives the redefinition rule above its meaning: with forward references, a spread written before a redefinition would have no defined answer for which version it names. Within a single query string the restriction does not apply — a fragment defined next to the operation may be spread before or after its definition.

The generated module is an embedded schema for an object type condition, and for an interface whose selections are shared by every member. A condition that resolves to per-member selections instead yields the TypedGql.Types.Union parameterized type at Fragments.Name.Union — not a struct — with the per-member embedded schemas at Fragments.Name.MemberType.

Examples

deffragment ~GQL"""
fragment UserFields on User {
  name
  email
}
"""

defgql :get_user, ~GQL"""
query GetUser($id: ID!) {
  user(id: $id) {
    ...UserFields
  }
}
"""

defgql(name, query_string)

(macro)

Defines a public GraphQL query function.

At compile time, parses and validates the query, generates typed response schemas, and defines a function that calls TypedGql.execute/3.

The query string may define its own fragments next to the operation. Such a definition shadows a deffragment of the same name: it is the one the server sees, and the registered source is not appended. Every fragment the string defines must also be spread by the operation — an unused definition is transmitted as written and the server rejects the document.

Examples

defgql :get_user, "query($id: ID!) { user(id: $id) { name } }"
# Generates: def get_user(variables, opts \\ [])

defgql :current_user, "query { currentUser { name email } }"
# Generates: def current_user(opts \\ [])

defgqlp(name, query_string)

(macro)

Defines a private GraphQL query function.

Same as defgql/2 but generates a defp instead of def.

sigil_GQL(query_string, modifiers)

(macro)

A sigil for writing GraphQL query strings that can be formatted by mix format.

Returns the query as a plain string — use it with defgql/defgqlp. Does not support interpolation (uppercase sigil convention).

To enable formatting, add TypedGql.Formatter to your .formatter.exs plugins.

Examples

defgql :get_user, ~GQL"""
  query GetUser($id: ID!) {
    user(id: $id) {
      name
      email
    }
  }
"""