gleamql

Package Version Hex Docs

A type-safe GraphQL client for Gleam.

Installation

gleam add gleamql

Quick Start

import gleamql
import gleamql/field
import gleamql/operation
import gleam/json
import gleam/hackney

pub type Country {
  Country(name: String, code: String)
}

pub fn main() {
  // Build the operation
  let country_op =
    operation.query("CountryQuery")
    |> operation.variable("code", "ID!")
    |> operation.field(
      field.object("country", fn() {
        use name <- field.field(field.string("name"))
        use code <- field.field(field.string("code"))
        field.build(Country(name:, code:))
      })
      |> field.arg("code", "code"),
    )

  // Send the request
  let assert Ok(Some(Country(name: "United Kingdom", code: "GB"))) =
    gleamql.new(country_op)
    |> gleamql.host("countries.trevorblades.com")
    |> gleamql.path("/graphql")
    |> gleamql.json_content_type()
    |> gleamql.send(hackney.send, [#("code", json.string("GB"))])
}

This generates:

query CountryQuery($code: ID!) {
  country(code: $code) {
    name
    code
  }
}

Examples

Looking for more examples? Check out the examples/ directory for complete, runnable example projects organized by difficulty:

Basics:

Advanced:

Each example is a self-contained Gleam project. Run any example with:

cd examples/01-basics/01-simple-query
gleam run

See the examples README for full details.

Key Features

Building Fields

// Scalars
field.string("name")
field.int("age")
field.bool("active")

// Optional fields and lists
field.optional(field.string("nickname"))
field.list(field.string("tags"))

// Nested objects
field.object("user", fn() {
  use name <- field.field(field.string("name"))
  use age <- field.field(field.int("age"))
  field.build(User(name:, age:))
})

Mutations

operation.mutation("CreatePost")
|> operation.variable("input", "CreatePostInput!")
|> operation.field(
  field.object("createPost", fn() {
    use id <- field.field(field.id("id"))
    field.build(Post(id:))
  })
  |> field.arg("input", "input")
)

Fragments

Reuse field selections across queries:

import gleamql/fragment

let user_fields = 
  fragment.on("User", "UserFields", fn() {
    use id <- field.field(field.id("id"))
    use name <- field.field(field.string("name"))
    field.build(User(id:, name:))
  })

operation.query("GetUsers")
|> operation.field(
  field.list(field.object("users", fn() {
    use user <- field.field(fragment.spread(user_fields))
    field.build(user)
  }))
)

Inline Fragments

Query unions and interfaces:

// Query a union type
field.object("search", fn() {
  use user <- field.field(field.inline_on("User", fn() {
    use name <- field.field(field.string("name"))
    field.build(name)
  }))
  use post <- field.field(field.inline_on("Post", fn() {
    use title <- field.field(field.string("title"))
    field.build(title)
  }))
  field.build(SearchResult(user:, post:))
})

Directives

Conditionally include fields:

import gleamql/directive

field.string("email")
|> field.with_directive(directive.include("showEmail"))
// Generates: email @include(if: $showEmail)

Documentation

For comprehensive guides and API documentation, visit hexdocs.pm/gleamql.

HTTP Clients

Works with any HTTP client:

License

Apache-2.0

Search Document