Skip to content

Variables ​

GraphQL variables allow you to parameterize your queries, making them reusable with different input values. GQLB provides full type safety for variable definitions and usage.

Basic Variable Usage ​

Define variables as the second argument to your operation:

typescript
import { b } from './generated'

const USER_QUERY = b.query('GetUser', { id: 'ID!' }, (b, v) => [
  b.user({ id: v.id }, b => [
    b.id(),
    b.name(),
    b.email(),
  ])
])

This generates:

graphql
query GetUser($id: ID!) {
  user(id: $id) {
    __typename
    id
    name
    email
  }
}

Variable Type Syntax ​

Variables use GraphQL type syntax as strings:

typescript
const VARIABLES_EXAMPLE = b.query('Example', {
  id: 'ID!',                    // Required ID
  name: 'String',               // Optional String
  limit: 'Int!',                // Required Int
  filters: 'PostFilters',       // Custom input type
  tags: '[String!]!',           // Required array of required strings
}, (b, v) => [
  // Use variables with v.fieldName
])

Common Variable Types ​

GraphQL TypeTypeScript TypeDescription
Stringstring | nullOptional string
String!stringRequired string
Intnumber | nullOptional integer
Int!numberRequired integer
Boolean!booleanRequired boolean
ID!string | numberRequired ID
[String!]!string[]Required array of strings
CustomInputCustomInputTypeCustom input type

Using Variables ​

Access variables through the second parameter of your builder function:

typescript
const FILTERED_POSTS = b.query('FilteredPosts', {
  authorId: 'ID!',
  limit: 'Int',
  published: 'Boolean'
}, (b, v) => [
  b.posts({ 
    authorId: v.authorId,     // Required variable
    limit: v.limit,           // Optional variable
    published: v.published    // Optional variable
  }, b => [
    b.id(),
    b.title(),
    b.publishedAt(),
  ])
])

Variable Type Validation ​

GQLB validates that variables match your schema:

typescript
// ✅ Valid - variable type matches field argument
const VALID = b.query('Valid', { id: 'ID!' }, (b, v) => [
  b.user({ id: v.id }, b => [  // Field expects ID!, variable provides ID!
    b.name()
  ])
])

// ❌ TypeScript error - type mismatch
const INVALID = b.query('Invalid', { id: 'String!' }, (b, v) => [
  b.user({ id: v.id }, b => [  // Field expects ID!, variable provides String!
    b.name()
  ])
])

Nullable Variables ​

GQLB handles nullable variables correctly:

typescript
const OPTIONAL_FILTER = b.query('OptionalFilter', {
  search: 'String',    // Optional - can be null
  limit: 'Int!'        // Required - cannot be null
}, (b, v) => [
  b.posts({
    search: v.search,  // string | null
    limit: v.limit     // number
  }, b => [
    b.id(),
    b.title(),
  ])
])

Custom Input Types ​

Use custom input types defined in your schema:

typescript
// Given this schema:
// input PostFilters {
//   tags: [String!]
//   minDate: DateTime
//   maxDate: DateTime
// }

const FILTERED_POSTS = b.query('FilteredPosts', {
  filters: 'PostFilters!'
}, (b, v) => [
  b.posts({ filters: v.filters }, b => [
    b.id(),
    b.title(),
    b.tags(),
  ])
])

// TypeScript knows the shape of filters:
type Variables = {
  filters: {
    tags?: string[]
    minDate?: Date
    maxDate?: Date
  }
}

Multiple Variables ​

Define multiple variables with different types:

typescript
const COMPLEX_QUERY = b.query('ComplexQuery', {
  userId: 'ID!',
  postLimit: 'Int',
  includeComments: 'Boolean!',
  sort: 'PostSort'
}, (b, v) => [
  b.user({ id: v.userId }, b => [
    b.id(),
    b.name(),
    b.posts({ 
      limit: v.postLimit,
      sort: v.sort 
    }, b => [
      b.id(),
      b.title(),
      ...(v.includeComments ? [
        b.comments(b => [
          b.id(),
          b.content(),
        ])
      ] : [])
    ])
  ])
])

Variable Usage in Mutations ​

Variables work the same way in mutations:

typescript
const CREATE_POST = b.mutation('CreatePost', {
  input: 'CreatePostInput!'
}, (b, v) => [
  b.createPost({ input: v.input }, b => [
    b.id(),
    b.title(),
    b.author(b => [
      b.id(),
      b.name(),
    ])
  ])
])

Default Values ​

GraphQL default values are handled by the server, but you can specify them:

typescript
// With default values in your schema:
// type Query {
//   posts(limit: Int = 10): [Post!]!
// }

const POSTS_WITH_DEFAULT = b.query('PostsWithDefault', (b) => [
  b.posts(b => [        // No limit argument - uses default
    b.id(),
    b.title(),
  ])
])

const POSTS_WITH_LIMIT = b.query('PostsWithLimit', {
  limit: 'Int'
}, (b, v) => [
  b.posts({ limit: v.limit }, b => [  // Override default
    b.id(),
    b.title(),
  ])
])

Runtime Usage ​

When executing queries, provide variables as a separate object:

typescript
import { USER_QUERY } from './queries'

// With Apollo Client
const { data } = await client.query({
  query: USER_QUERY.document(),
  variables: {
    id: "user-123"
  }
})

// With other GraphQL clients
const response = await graphqlClient.request(
  USER_QUERY.document(),
  { id: "user-123" }
)

Type Extraction ​

Extract variable types for function parameters:

typescript
import { VariablesOf } from '@gqlb/core'

type UserQueryVariables = VariablesOf<typeof USER_QUERY>
// Result: { id: string }

async function fetchUser(variables: UserQueryVariables) {
  return client.query({
    query: USER_QUERY.document(),
    variables
  })
}

Next Steps ​

Released under the MIT License.