Skip to content

wricardo/gqlcli

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gqlcli — GraphQL Client CLI & Library

Go Version License Go Report Card

Two tools in one:

  1. gqlcli CLI — A GraphQL client for querying any GraphQL API. Discover fields, execute queries and mutations, explore schemas—all from the command line.

  2. gqlcli library — Build GraphQL-backed CLI applications in Go. Write CLIs where GraphQL is the interface language, not subcommands and flags. Perfect for AI agents that can introspect schemas and construct queries.


🚀 Quick Start — Using the CLI

Installation

go install github.com/wricardo/gqlcli/cmd/gqlcli@latest
# or clone and build
git clone https://github.com/wricardo/gqlcli.git
cd gqlcli && make install

Basic Usage

# Discover what queries are available
gqlcli queries

# Find mutations related to "campaign"
gqlcli mutations --filter campaign

# Execute a query
gqlcli query --query "{ users { id name } }"

# Try against a different server
export GRAPHQL_URL=https://api.example.com/graphql
gqlcli queries --filter user

Real Examples

# List all Query fields with descriptions
gqlcli queries --desc

# Show mutation arguments and types
gqlcli mutations --args

# Explore schema in readable format
gqlcli introspect --format table

# Export schema as JSON
gqlcli introspect --format json > schema.json

# Execute a mutation with variables
gqlcli mutation \
  --mutation "mutation CreateUser(\$input: CreateUserInput!) { createUser(input: \$input) { id } }" \
  --input '{"name":"Alice","email":"alice@example.com"}'

# Use a query from a file
gqlcli query --query-file ./queries/getUser.graphql --variables '{"id":"123"}'

Different Output Formats

gqlcli queries --filter user -f json-pretty    # Pretty JSON
gqlcli queries --filter user -f table           # Aligned columns
gqlcli queries --filter user -f toon            # Token-optimized (default)
gqlcli queries --filter user -f llm             # Markdown for LLMs
gqlcli queries --filter user -f compact         # Minimal JSON

✨ CLI Features

🎯 Commands

  • query — Execute GraphQL queries with variables and multiple input methods
  • mutation — Execute mutations with auto-wrapped input objects
  • introspect — Download and explore full GraphQL schema
  • types — List all schema types with filtering
  • queries — Discover available Query fields instantly
  • mutations — Discover available Mutation fields instantly

📊 Output Formats

  • json / json-pretty — Pretty or compact JSON
  • table — Aligned columns for terminal viewing
  • toon — Token-optimized format (40-60% smaller) — default
  • llm — Markdown-friendly for AI/LLM consumption
  • compact — Minimal JSON (strips nulls)

🔐 Configuration

  • Default endpoint: http://localhost:8080/graphql
  • Override via --url flag or GRAPHQL_URL environment variable
  • Per-directory config file: .gqlcli.json with named environments (local, prod, qa, …)
  • Switch environments at runtime with --env prod
  • Bearer token authentication support
  • Custom HTTP headers per environment
  • Debug mode for request/response logging

📝 Input Methods

  • Inline: --query "{ users { id } }"
  • From files: --query-file queries/getUser.graphql
  • As arguments: query "{ ... }"
  • Variables inline: --variables '{"id":"123"}'
  • Variables from files: --variables-file vars.json
  • Named operations in multi-operation files

📚 Complete Usage Examples

Discovering Operations

# List all queries (TOON format — token-efficient)
gqlcli queries

# List with descriptions
gqlcli queries --desc

# Show arguments and types
gqlcli queries --args

# Filter by name
gqlcli queries --filter user
gqlcli mutations --filter campaign

# Different formats
gqlcli queries -f json-pretty
gqlcli mutations -f table

Executing Queries

# Simple query
gqlcli query --query "{ users { id name email } }"

# Query from file
gqlcli query --query-file ./queries/getUser.graphql

# With variables
gqlcli query \
  --query "query GetUser(\$id: ID!) { user(id: \$id) { id name } }" \
  --variables '{"id":"123"}'

# Variables from file
gqlcli query \
  --query-file ./queries/getUser.graphql \
  --variables-file ./variables.json

# Named operation (from multi-operation file)
gqlcli query \
  --query-file ./queries/operations.graphql \
  --operation "GetUser"

Mutations

# Basic mutation
gqlcli mutation \
  --mutation "mutation { createUser(name: \"Alice\") { id } }"

# With auto-wrapped input
gqlcli mutation \
  --mutation "mutation CreateUser(\$input: CreateUserInput!) { createUser(input: \$input) { id } }" \
  --input '{"name":"Alice","email":"alice@example.com"}'

# Alternative: explicit variables
gqlcli mutation \
  --mutation-file ./mutations/createUser.graphql \
  --variables '{"input":{"name":"Alice"}}'

Schema Exploration

# Full schema introspection
gqlcli introspect --format json-pretty > schema.json

# LLM-friendly schema
gqlcli introspect --format llm

# List all types
gqlcli types

# Filter types by name
gqlcli types --filter User

# Filter by kind
gqlcli types --kind OBJECT
gqlcli types --kind ENUM
gqlcli types --kind INPUT_OBJECT

# Compact output (good for piping)
gqlcli types -f compact

Environment Configuration

Option 1 — Environment variable

export GRAPHQL_URL="http://staging-api.example.com/graphql"
gqlcli queries

Option 2 — .gqlcli.json (per-directory config)

Create .gqlcli.json in your project directory to define named environments:

{
  "default": "local",
  "environments": {
    "local": {
      "url": "http://localhost:8080/graphql",
      "headers": {
        "Authorization": "Bearer dev-token"
      }
    },
    "staging": {
      "url": "http://staging-api.example.com/graphql",
      "headers": {
        "Authorization": "Bearer staging-token",
        "X-Tenant": "acme"
      }
    },
    "prod": {
      "url": "https://api.example.com/graphql",
      "headers": {
        "Authorization": "Bearer prod-token"
      }
    }
  }
}
# Uses "local" (the default)
gqlcli queries

# Switch to prod
gqlcli queries --env prod
gqlcli query --query "{ users { id } }" --env prod

# Override URL on top of a named env
gqlcli queries --env staging --url http://other-host/graphql

Priority (lowest → highest): hardcoded default → .gqlcli.json env → GRAPHQL_URL--url flag

Advanced: Save Results to File

# Query result to file
gqlcli query --query "{ users { id } }" --output results.json

# Schema to file
gqlcli introspect --format json --output schema.json

# Types list to file
gqlcli types --output types.json

🔧 Command Reference

Global Flags

-u, --url VALUE       GraphQL endpoint (default: http://localhost:8080/graphql, env: GRAPHQL_URL)
--env VALUE           Environment to use from .gqlcli.json (e.g. local, prod)
-f, --format VALUE    Output format: json, json-pretty, table, compact, toon, llm (default: toon)
-p, --pretty          Pretty print JSON output
-h, --help            Show help

query Command

-q, --query STRING           GraphQL query
--query-file PATH            Read query from file
-v, --variables JSON         Query variables as JSON
--variables-file PATH        Read variables from file
-o, --operation STRING       Named operation to execute
-f, --format FORMAT          Output format
--output FILE                Write to file
-u, --url URL                GraphQL endpoint (env: GRAPHQL_URL)
--env VALUE                  Environment from .gqlcli.json
-d, --debug                  Enable HTTP debug logging

mutation Command

-m, --mutation STRING        GraphQL mutation
--mutation-file PATH         Read mutation from file
--input JSON                 Input object (auto-wrapped as {"input":{...}})
-v, --variables JSON         Variables as JSON
--variables-file PATH        Read variables from file
-o, --operation STRING       Named operation
-f, --format FORMAT          Output format
--output FILE                Write to file
-u, --url URL                GraphQL endpoint (env: GRAPHQL_URL)
--env VALUE                  Environment from .gqlcli.json
-d, --debug                  Enable HTTP debug logging

queries Command

--desc                       Include field descriptions
--args                       Include field arguments with types
--filter PATTERN             Filter by name (case-insensitive)
-f, --format FORMAT          Output format (default: toon)
-u, --url URL                GraphQL endpoint (env: GRAPHQL_URL)
--env VALUE                  Environment from .gqlcli.json
-d, --debug                  Enable debug logging

mutations Command

--desc                       Include field descriptions
--args                       Include field arguments with types
--filter PATTERN             Filter by name (case-insensitive)
-f, --format FORMAT          Output format (default: toon)
-u, --url URL                GraphQL endpoint (env: GRAPHQL_URL)
--env VALUE                  Environment from .gqlcli.json
-d, --debug                  Enable debug logging

introspect Command

-f, --format FORMAT          Output format (default: llm)
-o, --output FILE            Write schema to file
-p, --pretty                 Pretty print JSON
-u, --url URL                GraphQL endpoint (env: GRAPHQL_URL)
--env VALUE                  Environment from .gqlcli.json
-d, --debug                  Enable debug logging

types Command

--filter PATTERN             Filter by name (substring match)
--kind KIND                  Filter by kind (OBJECT, ENUM, INPUT_OBJECT, SCALAR, INTERFACE, UNION)
-f, --format FORMAT          Output format (default: compact)
-u, --url URL                GraphQL endpoint (env: GRAPHQL_URL)
--env VALUE                  Environment from .gqlcli.json
-d, --debug                  Enable debug logging

📚 Using as a Library

The gqlcli package provides two ways to build CLI tools:

Mode Use Case
HTTP Mode Build a CLI that queries external GraphQL APIs over HTTP
Inline Mode Build a GraphQL-backed CLI with inline execution (using gqlgen) — perfect for AI agents and schema-driven CLIs

See sections below for detailed examples of each mode.


📦 Installation

CLI Tool

go install github.com/wricardo/gqlcli/cmd/gqlcli@latest

Or clone and build:

git clone https://github.com/wricardo/gqlcli.git
cd gqlcli
make install
gqlcli --help

As a Go Library

go get github.com/wricardo/gqlcli

HTTP Mode — Query External GraphQL APIs

Build a CLI that connects to external GraphQL servers over HTTP. Useful for API testing, schema exploration, and CI/CD pipelines:

package main

import (
	"os"
	"log"
	"github.com/urfave/cli/v2"
	"github.com/wricardo/gqlcli/pkg"
)

func main() {
	cfg := &gqlcli.Config{
		URL:     "http://localhost:8080/graphql",
		Format:  "toon",
		Timeout: 30,
	}

	builder := gqlcli.NewCLIBuilder(cfg)
	app := &cli.App{
		Name: "gql",
		Usage: "GraphQL CLI",
	}

	builder.RegisterCommands(app)
	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}

Inline Mode — GraphQL-Backed CLI Applications

Build GraphQL-native CLI applications where GraphQL is the interface language, not subcommands and flags. This is especially powerful for AI agents that can introspect schemas and construct queries dynamically.

Why GraphQL for CLIs:

Traditional CLI GraphQL-Native CLI
myapp --user-type=active --limit 10 --format json myapp query '{ users(type: "active", limit: 10) { id name } }'
Multiple commands for different operations One unified query language
AI must learn your CLI's custom flags AI naturally understands GraphQL
Hard to combine operations Execute multiple queries in parallel
Schema is implicit Schema is explicit and queryable

If you have a gqlgen schema, you can run operations in-process without an HTTP server. This is useful for building a CLI that ships alongside your application binary.

package main

import (
	"log"
	"os"

	"github.com/urfave/cli/v2"
	gqlcli "github.com/wricardo/gqlcli/pkg"

	"github.com/myorg/myapp/graph" // your gqlgen package
)

func main() {
	// 1. Create your gqlgen ExecutableSchema.
	r := graph.NewResolver()
	execSchema := graph.NewExecutableSchema(graph.Config{Resolvers: r})

	// 2. Inline executor — runs operations directly in-process.
	//    WithSchemaHints attaches compact type SDL to validation errors.
	exec := gqlcli.NewInlineExecutor(execSchema,
		gqlcli.WithSchemaHints(),
	)

	// 3. Command set — adds query, mutation, describe, types commands.
	commands := gqlcli.NewInlineCommandSet(exec)

	// 4. Mount onto any urfave/cli app.
	app := &cli.App{Name: "myapp", Usage: "CLI for my GraphQL API"}
	commands.Mount(app)

	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}

This adds the following subcommands:

Command Description
query Execute a query (TOON format by default)
mutation Execute a mutation (JSON format by default)
describe TYPE Print SDL definition of a type
types List all types in the schema

Schema hints — when WithSchemaHints() is enabled, validation errors include a compact SDL description of the referenced type:

Error: Cannot query field "titl" on type "Book".
Schema hint:
type Book {
  id: ID!
  title: String!
  author: Author!
}

describe Command (Inline-Only)

Available only in inline execution mode. Print the SDL definition of a type:

# Describe a type
./myapp describe Query
./myapp describe Book
./myapp describe AddBookInput

# Output shows field signatures and relationships
type Book {
  id: ID!
  title: String!
  author: Author!
}

Useful for AI agents to discover schema structure before constructing queries.


Complete Example

See example/README.md for a complete working example of a GraphQL-native CLI — no subcommands, no flags, just GraphQL queries and mutations. The example demonstrates:

  • GraphQL as the interface — Execute queries like ./myapp query '{ books { id title author { name } } }'
  • Schema introspection — AI agents can discover capabilities with ./myapp describe Book
  • Parallel execution — Multiple top-level queries in one command
  • Inline execution — No HTTP server needed, runs in-process against a gqlgen schema
  • File-based persistence — Data stored in store.json
  • Forced resolvers — Using @goField(forceResolver: true) for lazy-loading
  • Split schema files — Organized with follow-schema layout

This is the ideal paradigm for:

  • AI agents — Introspect schema, construct queries, explore data
  • CLI automation — Write complex queries instead of chaining commands
  • Consistent interfaces — GraphQL works everywhere, agents already understand it

See example/README.md for detailed setup and usage.


🏗️ Architecture

Core Components

Component Purpose
Config Configuration holder (URL, format, timeout)
CLIBuilder HTTP-based CLI command generator
InlineExecutor In-process executor for gqlgen schemas
InlineCommandSet CLI commands backed by an InlineExecutor
TokenStore JWT persistence at ~/.{appName}/token
Describer Introspects a schema and returns SDL for a type
Formatter Output format converter (JSON, table, TOON, etc.)
FormatterRegistry Manages available formatters

Package Structure

pkg/
├── cli.go              # HTTP-based CLI command builders (CLIBuilder)
├── client.go           # HTTP GraphQL client
├── inline.go           # InlineExecutor — in-process execution
├── inline_commands.go  # InlineCommandSet — query/mutation/describe/login commands
├── projectconfig.go    # .gqlcli.json loader and environment resolution
├── token.go            # TokenStore — JWT persistence and parsing
├── describe.go         # Describer — schema introspection and SDL formatting
├── formatter.go        # Output formatters
└── types.go            # Type definitions and interfaces

🔌 Extending the Library

Add a Custom Formatter

package main

import "github.com/wricardo/gqlcli/pkg"

type CSVFormatter struct{}

func (f *CSVFormatter) Format(data map[string]interface{}) (string, error) {
	// Your CSV formatting logic
	return csvOutput, nil
}

func (f *CSVFormatter) Name() string {
	return "csv"
}

// Usage:
registry := gqlcli.NewFormatterRegistry()
registry.Register("csv", &CSVFormatter{})

Custom Client Implementation

type CachedClient struct {
	cache map[string]interface{}
}

func (c *CachedClient) Execute(ctx context.Context, mode gqlcli.ExecutionMode, opts gqlcli.QueryOptions) (map[string]interface{}, error) {
	// Check cache first
	// Fall back to HTTP if not found
	return result, nil
}

📊 Use Cases

API Development & Testing

# Discover available operations
gqlcli queries
gqlcli mutations

# Test a mutation
gqlcli mutation \
  --mutation-file ./test/mutations/createUser.graphql \
  --variables-file ./test/variables.json

Schema Documentation

# Generate schema documentation
gqlcli introspect --format llm > SCHEMA.md

# List all types
gqlcli types --format json-pretty > types.json

CI/CD Pipelines

# Verify schema changes
gqlcli introspect --format json > current-schema.json
git diff previous-schema.json current-schema.json

AI/LLM Integration

# Get schema in token-efficient format
gqlcli introspect --format toon

# Discover operations for LLM context
gqlcli queries --desc --format toon
gqlcli mutations --desc --args --format toon

🧪 Testing

# Run all tests
make test

# Test with coverage
make test-coverage

# Run linter
make lint

# Format code
make fmt

⚙️ Development

# Build
make build

# Build and test
make dev

# Install locally
make install

# Clean artifacts
make clean

# View all available commands
make help

🔒 Error Handling

Rich error messages with context:

🚨 GraphQL Validation/Execution Errors:

  ❌ 1. Cannot query field "unknown" on type "Query"
     📂 Path: unknown
     🏷️  Code: GRAPHQL_VALIDATION_FAILED
     📍 Position: Line 1, Column 3

📝 Query that caused the error:
   1 | { unknown }

🌟 Why gqlcli?

  • Zero Dependencies — Single binary, no runtime dependencies
  • Production-Ready — Extensively tested and battle-hardened
  • Token-Efficient — TOON format reduces tokens by 40-60%
  • Extensible — Clean interfaces for custom formatters and clients
  • Flexible Input — Multiple ways to specify queries and variables
  • DevOps Friendly — Perfect for scripts, CI/CD, and automation
  • Open Source — MIT licensed, community-driven

🤝 Contributing

We welcome contributions! Whether it's bug fixes, features, documentation, or examples.

Getting Started

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Make your changes
  4. Run tests: make test
  5. Run linter: make lint
  6. Commit: git commit -m 'Add amazing feature'
  7. Push: git push origin feature/amazing-feature
  8. Open a Pull Request

Guidelines

  • Keep commits focused and descriptive
  • Add tests for new functionality
  • Update documentation as needed
  • Follow Go conventions and style
  • Run make fmt before committing

📝 License

MIT License — see LICENSE file for details.


📞 Support & Community


🙏 Acknowledgments

Built with:


📈 Project Status

Active Development — Maintained and open to contributions.

Latest features:

  • .gqlcli.json project config — named environments with URL and custom headers, --env flag
  • ✅ Inline execution — run operations in-process against a gqlgen schema (no HTTP server)
  • ✅ Schema hints — attach type SDL to GraphQL validation errors
  • ✅ Token store — JWT persistence and parsing for login/logout/whoami
  • ✅ Query and Mutation operation discovery (queries, mutations commands)
  • ✅ Token-optimized TOON format (default)
  • ✅ Environment variable support (GRAPHQL_URL)
  • ✅ Multiple output formats
  • ✅ Extensible architecture

Made with ❤️ for the GraphQL community

About

Graphql command-line client

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors