gqlkit

module
v0.14.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 6, 2026 License: Apache-2.0

README

gqlkit

gqlkit is the code generator: it reads a GraphQL schema in SDL and writes a typed client SDK, in Go (gqlkit generate) or TypeScript (gqlkit generate-ts). The SDK has one builder per query and mutation, one type per GraphQL type, and a field selector per object type, so you compose operations in code and pick fields at the call site instead of writing query strings.

This folder is also a Go module (github.com/ubgo/gqlkit/gqlkit) that exposes the same generators as a Go API. A generated SDK never imports this module.

Contents

Install

Quick install for macOS and Linux:

curl -sL https://raw.githubusercontent.com/ubgo/gqlkit/main/gqlkit/install.sh | sh

Or download a binary for any platform from GitHub Releases, or build it with Go:

go install github.com/ubgo/gqlkit/gqlkit/cmd/gqlkit@latest   # newest release
go install github.com/ubgo/gqlkit/gqlkit/cmd/[email protected]  # pinned

Releases consumable by Go are tagged in the path-prefixed form Go requires for a nested module (gqlkit/v0.14.0), starting at v0.11.0. The [email protected] tags are what GitHub Releases and the install script use; both forms point at the same commits, and gqlkit version reports the module version it was built from either way.

Check the install:

gqlkit version

Generate a Go SDK

You need a schema file (fetch one with gqlkit-sdl if you only have an endpoint) and a Go module to generate into. From the module root:

gqlkit generate -s schema.graphql -o ./sdk -m "$(go list -m)/sdk"
go build ./...

-m is the import path of the output directory, not of your module: the generated packages import one another through it. The generated SDK needs Go 1.24 or later; a build guard makes older toolchains fail to compile it rather than misbehave. Then use the SDK; every import comes from the generated code:

import (
	"context"

	"yourmodule/sdk/fields"
	"yourmodule/sdk/graphqlclient"
	"yourmodule/sdk/queries"
)

func listTodos(ctx context.Context) error {
	client := graphqlclient.NewClient("https://api.example.com/graphql",
		graphqlclient.WithAuthToken(token),
	)
	qr := queries.NewQueryRoot(client)

	todos, err := qr.Todos().
		Select(func(f *fields.TodoFields) {
			f.ID().Text().User(func(u *fields.UserFields) { u.Name() })
		}).
		Execute(ctx)
	if err != nil {
		return err
	}
	_ = todos // []types.Todo; fields you did not select hold zero values
	return nil
}

Step by step, with every flag explained: Generate a Go SDK. Runnable: example-cli/generate-go.sh.

Generate a TypeScript SDK

npm i gqlkit-ts
gqlkit generate-ts -s schema.graphql -o ./src/sdk
import { GraphQLClient } from "gqlkit-ts";
import { QueryRoot } from "./sdk/queries";

const qr = new QueryRoot(new GraphQLClient("https://api.example.com/graphql", { authToken }));

const todos = await qr.todos().select((t) => t.id().text().user((u) => u.name())).execute();
// todos: { id: string; text: string; user: { name: string } }[]

The generated files import their runtime from gqlkit-ts, so the app needs that package. Step by step: Generate a TypeScript SDK. Runnable: example-cli/generate-ts.sh.

Commands and flags

Command What it does
gqlkit generate Generate a Go SDK
gqlkit generate-ts Generate a TypeScript SDK
gqlkit version Print the version
gqlkit completion <shell> Print a shell completion script (bash, zsh, fish, powershell)
Flag Short generate generate-ts Default Meaning
--schema -s required required — SDL file, or a quoted glob such as './schema/*.graphql'
--output -o yes yes ./sdk Output directory; created if missing, files overwritten, never deleted
--config -c yes yes — config.jsonc with scalar bindings and other settings; a path that does not exist is an error
--module -m yes — nearest go.mod (walking up) + -o Import path of the output directory
--package -p yes — sdk Name shown in the progress output; a value containing / is used as the import path
--prune — yes yes off After a successful run, delete files in the output directory that carry the gqlkit banner but were not written by this run; files without the banner are never touched
--dry-run — yes yes off With --prune: list what would be deleted, delete nothing (an error without --prune)

Both commands exit 0 on success and 1 on any failure. Which import-path flag to pass in which situation: decision table.

Scalar bindings (config.jsonc)

Custom scalars in the schema (scalar DateTime, scalar Cursor) need to be told which language type to use; anything unbound becomes any. Go and TypeScript use different formats, so keep one file per language:

// Go: go.config.jsonc
{
  "bindings": {
    "DateTime": { "model": "time.Time" },
    "Cursor": { "model": "string" },
    "UUID": { "model": "github.com/google/uuid.UUID" }
  }
}
// TypeScript: ts.config.jsonc
{
  "bindings": {
    "DateTime": "string",
    "Cursor": "string",
    "JSON": { "type": "JsonValue", "import": "type-fest" }
  }
}

Go already maps Int64, Int32, Uint, Uint64, Uint32, Float64, Float32, Time (time.Time) and JSON (json.RawMessage) without a config.

The same files hold two more settings:

  • Go inputs: how nullable input-object fields are generated. The default "pointer" gives *T, which cannot send an explicit null. "opt" gives inputs.Opt[T] with three states (unset, inputs.Null[T](), inputs.Some(v)), the only way to clear a field in an update. Set it for everything with "inputs": { "optional": "opt" }, or per input type or field with "overrides": { "UpdateTodoInput.tags": "opt" }. Opt needs Go 1.24 or later.
  • TypeScript nullable: nullable outputs are T | null by default. "nullable": "null-undefined" (or nullableOverrides per type or field) widens them to T | null | undefined for code written against older SDKs. A TypeScript binding can also name a codec ("decode", "encode", "codecImport") so values are converted, not just typed. The full key list and the built-in table: config.jsonc. Which binding to pick per scalar: Choosing a scalar binding.

What gets generated

Go package TypeScript folder Holds
queries, mutations queries/, mutations/ The roots (NewQueryRoot, new QueryRoot) and one builder per root field
fields fields/ One selector per object, interface and union type (TodoFields; SearchResultFields with OnTodo / OnUser)
types types/ One type per GraphQL object or interface; in Go also a <Name>Value wrapper per union and interface (Typename, Value, Raw)
inputs inputs/ Input object types; in Go also Opt[T], Some and Null
enums enums/ Enums (Go: typed string constants; TS: enum)
scalars scalars/ Custom scalars as type aliases, per your bindings
builder builder/ Go: the builder runtime itself. TS: a re-export of gqlkit-ts
graphqlclient — Go: the HTTP client (NewClient, WithAuthToken, GraphQLErrors)
batch — Go: RunQueries and RunMutations. TS: batch comes from gqlkit-ts

The guides for using each part: Go guides and TypeScript guides.

Use the generators from Go

Everything the CLI does is available as clientgen.New (Go SDK) and clientgents.New (TypeScript SDK):

gen, err := clientgen.New(&clientgen.Config{
	SchemaPath: "schema.graphql",
	OutputDir:  "./sdk",
	ModulePath: "example.com/app/sdk",
	ConfigPath: "go.config.jsonc",
})
if err != nil {
	log.Fatal(err)
}
if err := gen.Generate(); err != nil {
	log.Fatal(err)
}

The full program, every Config field, and fetching from Go: Run the generators from Go code. When to prefer this over the CLI: CLI or Go program. Runnable: example-go-mockapi/cmd/generate, example-ts/cmd/generate.

Packages in this module

Package Purpose
cmd/gqlkit The CLI
pkg/clientgen The Go SDK generator (clientgen.New)
pkg/clientgents The TypeScript SDK generator (clientgents.New)
pkg/templater The Go templates the generators render
pkg/builder, pkg/graphqlclient, pkg/batch Upstream versions of the runtime packages emitted into every Go SDK, kept in sync with the templates and tested here. See pkg/builder and pkg/batch
pkg/schemagql, pkg/typegql, pkg/util, pkg/writer Internal helpers: schema loading, GraphQL to Go type mapping, file writing

Pitfalls

  • Wrong -m. Passing your module path (example.com/app) instead of the SDK's (example.com/app/sdk) generates imports that do not resolve. Without -m, gqlkit uses the nearest go.mod above the working directory, and fails with an error if there is none or the output directory is outside that module.
  • Stale files. Without --prune the generator overwrites but never deletes, so a builder for a removed operation stays behind and breaks the build. Pass --prune (preview with --dry-run); see When to regenerate.
  • An unquoted glob. The shell expands ./schema/*.graphql into several arguments before gqlkit sees it. gqlkit refuses the extra arguments and exits 1 with unexpected argument(s): ... and a hint to quote the glob, e.g. -s './schema/*.graphql'. Quote it.
  • One config for both languages. A Go config passed to generate-ts writes broken scalar aliases without an error.
  • Go results are not narrowed. Unselected fields are zero values, not compile errors; only the TypeScript SDK narrows. See Go or TypeScript.

Directories

Path Synopsis
cmd
gqlkit command
pkg
batch
Package batch merges multiple builders into a single GraphQL operation with aliased root fields, so callers can fetch several queries (or run several mutations) in one HTTP round trip.
Package batch merges multiple builders into a single GraphQL operation with aliased root fields, so callers can fetch several queries (or run several mutations) in one HTTP round trip.
builder
Package builder provides the runtime foundation for generated GraphQL operation builders.
Package builder provides the runtime foundation for generated GraphQL operation builders.
clientgen
Package clientgen is the main orchestrator for generating a type-safe Go client SDK from a parsed GraphQL schema.
Package clientgen is the main orchestrator for generating a type-safe Go client SDK from a parsed GraphQL schema.
clientgents
Package clientgents is the main orchestrator for generating a type-safe TypeScript client SDK from a parsed GraphQL schema.
Package clientgents is the main orchestrator for generating a type-safe TypeScript client SDK from a parsed GraphQL schema.
graphqlclient
Package graphqlclient provides a lightweight HTTP client for executing GraphQL queries and mutations against a remote endpoint.
Package graphqlclient provides a lightweight HTTP client for executing GraphQL queries and mutations against a remote endpoint.
schemagql
Package schemagql provides utilities for loading and parsing GraphQL SDL schema files into the gqlparser AST representation.
Package schemagql provides utilities for loading and parsing GraphQL SDL schema files into the gqlparser AST representation.
templater
Package templater provides a Template wrapper around Go's text/template with pre-registered helper functions (pascalCase, camelCase, formatDesc, jsonTag, etc.) and embedded template files used by the Go code generator.
Package templater provides a Template wrapper around Go's text/template with pre-registered helper functions (pascalCase, camelCase, formatDesc, jsonTag, etc.) and embedded template files used by the Go code generator.
typegql
Package typegql maps GraphQL scalar type names to Go types.
Package typegql maps GraphQL scalar type names to Go types.
util
Package util provides string conversion utilities (PascalCase, camelCase, snake_case) and small helper functions used throughout the gqlkit code generators.
Package util provides string conversion utilities (PascalCase, camelCase, snake_case) and small helper functions used throughout the gqlkit code generators.
writer
Package writer provides utilities for writing generated Go source files to disk.
Package writer provides utilities for writing generated Go source files to disk.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL