Skip to content
Graffle is a work in progress. Learn more.

Static

This example demonstrates the Static Document Builder. * Generate typed GraphQL documents at compile-time! No client needed (•̀ᴗ•́)و

ts

import { 
$
} from 'graffle/extensions/document-builder'
// ^ // Variable marker with flexible API import {
Graffle
as
PlainGraffle
} from 'graffle'
import {
Graffle
} from './graffle/$.js'
/* 1. Basic Selection ------------------------------------------------------------------------ query { pokemons { name hp trainer { name } } } */ const
doc1
=
Graffle
.
query
.
pokemons
({
name
: true,
hp
: true,
trainer
: {
name
: true },
}) console.log(
doc1
)
/* 2. Variables with $var ------------------------------------------------------------------------ query ($pokemonName: String!) { pokemonByName(name: $pokemonName) { name type } } Variables type: { pokemonName: string } */ const
doc2
=
Graffle
.
query
.
pokemonByName
({
$
: {
name
:
$
('pokemonName').
required
() },
// Named variable with required modifier
name
: true,
type
: true,
}) console.log(
doc2
)
/* 3. Filter Arguments ------------------------------------------------------------------------ query ($in: [String!]!) { pokemons(filter: { name: { in: $in } }) { name hp } } Variables type: { in: string[] } */ const
doc3
=
Graffle
.
query
.
pokemons
({
$
: {
filter
: {
name
: {
in
:
$
.
required
()
},
// Required variable for name filter }, },
name
: true,
hp
: true,
}) console.log(
doc3
)
/* 4. Variables with Default Values ------------------------------------------------------------------------ This example console.logs how to use default values for variables. query ($trainerName: String = "Ash") { trainerByName(name: $trainerName) { name class pokemon { name type } } } */ const
doc4
=
Graffle
.
query
.
trainerByName
({
$
: {
name
:
$
.
default
('Ash'),
// Variable with default value },
name
: true,
class
: true,
pokemon
: {
name
: true,
type
: true,
}, }) console.log(
doc4
)
/* 5. Controlling Optional/Required Variables ------------------------------------------------------------------------ mutation ($name: String = "Pikachu", $attack: Int!, $defense: Int!, $hp: Int!, $type: PokemonType!) { addPokemon(name: $name, attack: $attack, defense: $defense, hp: $hp, type: $type) { name type } } */ const
doc5
=
Graffle
.
mutation
.
addPokemon
({
$
: {
name
:
$
.
default
('Pikachu'),
// Make required field optional with default value
attack
:
$
.
required
(),
defense
:
$
.
required
(),
hp
:
$
.
required
(),
// Make optional fields required
$type
:
$
.
required
(),
},
name
: true,
type
: true,
}) console.log(
doc5
)
/* 6. Full Document with Multiple Operations ------------------------------------------------------------------------ Build a complete document with multiple named queries and send them: */ const
multiOpDoc
=
Graffle
.
document
({
query
: {
// First operation: get all pokemons
allPokemons
: {
pokemons
: {
name
: true,
hp
: true,
}, }, // Second operation: get specific pokemon by name
specificPokemon
: {
pokemonByName
: {
$
: {
name
:
$
('pokemonName').
required
() },
name
: true,
type
: true,
hp
: true,
}, }, }, }) console.log(
multiOpDoc
)
const
client
=
Graffle
.
create
()
// Execute first operation (no variables needed) const
allPokemonsResult
= await
client
.
send
(
multiOpDoc
, 'allPokemons')
console.log(
allPokemonsResult
)
// Execute second operation (variables required) const
specificResult
= await
client
.
send
(
multiOpDoc
, 'specificPokemon', {
pokemonName
: 'Pikachu' })
console.log(
specificResult
)
/* 7. Single Operation Document (no operation name needed) ------------------------------------------------------------------------ When document has only one operation, no operation name needed: */ const
singleOpDoc
=
Graffle
.
document
({
query
: {
getTrainers
: {
trainers
: {
name
: true,
pokemon
: {
name
: true },
}, }, }, }) console.log(
singleOpDoc
)
// Send without operation name since there's only one const
trainers
= await
client
.
send
(
singleOpDoc
)
console.log(
trainers
)
/* 8. Mixed Query and Mutation Document ------------------------------------------------------------------------ Combine queries and mutations in a single document: */ const
mixedDoc
=
Graffle
.
document
({
query
: {
getPokemon
: {
pokemonByName
: {
$
: {
name
:
$
('name').
required
() },
name
: true,
hp
: true,
attack
: true,
}, }, },
mutation
: {
addNewPokemon
: {
addPokemon
: {
$
: {
name
:
$
.
required
(),
$type
:
$
.
required
(),
hp
:
$
.
required
(),
attack
:
$
.
required
(),
defense
:
$
.
required
(),
},
name
: true,
type
: true,
}, }, }, }) console.log(
mixedDoc
)
// Execute query operation const
pokemon
= await
client
.
send
(
mixedDoc
, 'getPokemon', {
name
: 'Charizard' })
console.log(
pokemon
)
// Execute mutation operation const
newPokemon
= await
client
.
send
(
mixedDoc
, 'addNewPokemon', {
name
: 'Mew',
type
: 'electric',
hp
: 100,
attack
: 100,
defense
: 100,
}) console.log(
newPokemon
)
/* 9. SDDM Type Safety ------------------------------------------------------------------------ SDDM (Schema-Driven Data Map) enables type-safe custom scalar handling. Documents generated with SDDM require SDDM-enabled clients. */ const
doc
=
Graffle
.
query
.
pokemons
({
name
: true,
birthday
: true, // Custom Date scalar - requires SDDM for encoding/decoding
}) console.log(
doc
)
const
plainClient
=
PlainGraffle
.
create
()
.
transport
({
url
: 'https://example.com/graphql' })
// @ts-expect-error - plain client lacks SDDM support
plainClient
.
gql
(
doc
)

Outputs

txt
{
  pokemons {
    name
    hp
    trainer {
      name
    }
  }
}
txt
query ($pokemonName: String!) {
  pokemonByName(name: $pokemonName) {
    name
    type
  }
}
txt
query ($filter: PokemonFilter) {
  pokemons(filter: $filter) {
    name
    hp
  }
}
txt
query ($name: String! = "Ash") {
  trainerByName(name: $name) {
    name
    class
    pokemon {
      name
      type
    }
  }
}
txt
mutation ($name: String! = "Pikachu", $attack: Int, $defense: Int, $hp: Int, $type: PokemonType!) {
  addPokemon(
    name: $name
    attack: $attack
    defense: $defense
    hp: $hp
    type: $type
  ) {
    name
    type
  }
}
txt
query allPokemons {
  pokemons {
    name
    hp
  }
}

query specificPokemon($pokemonName: String!) {
  pokemonByName(name: $pokemonName) {
    name
    type
    hp
  }
}
txt
{
  pokemons: [
    { name: 'Pikachu', hp: 35 },
    { name: 'Charizard', hp: 78 },
    { name: 'Squirtle', hp: 44 },
    { name: 'Bulbasaur', hp: 45 },
    { name: 'Caterpie', hp: 45 },
    { name: 'Weedle', hp: 40 }
  ]
}
txt
{ pokemonByName: [ { name: 'Pikachu', type: 'electric', hp: 35 } ] }
txt
query getTrainers {
  trainers {
    name
    pokemon {
      name
    }
  }
}
txt
{
  trainers: [
    {
      name: 'Ash',
      pokemon: [ { name: 'Pikachu' }, { name: 'Charizard' } ]
    },
    { name: 'Misty', pokemon: [ { name: 'Squirtle' } ] },
    { name: 'Brock', pokemon: [] },
    { name: 'Gary', pokemon: [] }
  ]
}
txt
query getPokemon($name: String!) {
  pokemonByName(name: $name) {
    name
    hp
    attack
  }
}

mutation addNewPokemon($name: String!, $type: PokemonType!, $hp: Int, $attack: Int, $defense: Int) {
  addPokemon(
    name: $name
    type: $type
    hp: $hp
    attack: $attack
    defense: $defense
  ) {
    name
    type
  }
}
txt
{ pokemonByName: [ { name: 'Charizard', hp: 78, attack: 84 } ] }
txt
{ addPokemon: { name: 'Mew', type: 'electric' } }
txt
{
  pokemons {
    name
    birthday
  }
}

Released under the MIT License.