Skip to content
/ gql Public

The Missing GraphQL Schema Builder for Golang

Notifications You must be signed in to change notification settings

kadirpekel/gql

Repository files navigation

Gql - The Missing GraphQL Schema Builder for Golang

A flexible and type-safe GraphQL schema builder for Go that automatically generates GraphQL schemas from Go types and functions. It nicely stands on the shoulders of github.com/graphql-go/graphql, a battle-tested package widely used in production environments.

Why Gql?

GraphQL in Go can be frustrating. If you've tried gqlgen, you might have been overwhelmed by the code generation, hidden complexity, and unnecessary bloat. On the other hand, graphql-go/graphql offers a more manual approach but comes with verbosity and an unintuitive structure that makes schema definition cumbersome. Gql is here to solve that problem by providing a flexible, type-safe, and intuitive way to build GraphQL schemas directly from Go types and functions—without code generation or unnecessary boilerplate.

Features

  • Type-Safe: Uses Go types to define your GraphQL schema effortlessly.
  • Automatic Schema Generation: No need to manually define GraphQL types; just annotate your Go structs.
  • Built on graphql-go/graphql: Leverages an established GraphQL implementation for Go.
  • Flexible and Extensible: Supports custom resolvers, input types, and mutations.
  • Flexible Resolver Signature: Resolver methods can accept context.Context, graphql.ResolveInfo, and input structs in any order and combination.
  • GQL Tags for Struct Fields: Uses struct tags to define GraphQL fields and arguments easily.

Installation

go get github.com/kadirpekel/gql

Quick Start

Here's a simple example of how to define and use a GraphQL schema with gql:

package main

import (
	"context"
	"fmt"
	"github.com/graphql-go/graphql"
	"github.com/kadirpekel/gql"
)

// Struct fields are annotated with gql tags to define GraphQL schema
// The tag format is `gql:"fieldName[,modifier]"`
// Example: `gql:"ID,nonNull"` ensures the field is required in GraphQL

type User struct {
	ID        string `gql:"ID"`
	FirstName string `gql:"firstName"`
	LastName  string `gql:"lastName"`
}

func (u *User) FullName() (string, error) {
	return fmt.Sprintf("%s %s", u.FirstName, u.LastName), nil
}

type UserInput struct {
	ID string `gql:"ID,nonNull"`
}

type query struct{}

func (q query) GetUser(ctx context.Context, args UserInput, info graphql.ResolveInfo) (*User, error) {
	return &User{ID: args.ID, FirstName: "John", LastName: "Doe"}, nil
}

func (q query) ListUsers(info graphql.ResolveInfo) ([]*User, error) {
	return []*User{
		{ID: "1", FirstName: "John", LastName: "Doe"},
		{ID: "2", FirstName: "Jane", LastName: "Doe"},
	}, nil
}

func main() {
	schema, err := gql.NewSchemaBuilder().
		WithQuery(query{}).
		BuildSchema()

	if err != nil {
		panic(err)
	}

	// Use the schema with your GraphQL server
}

GQL Tags for Struct Fields

The gql struct tags define GraphQL schema properties directly on Go structs:

  • Basic Mapping: gql:"fieldName" maps the Go struct field to a GraphQL field.
  • Modifiers: Add modifiers such as nonNull for required fields.
  • Example Usage:
type User struct {
	ID   string `gql:"ID,nonNull"` // Required GraphQL ID field
	Name string `gql:"name"`       // Maps to GraphQL "name" field
}

Resolver Method Signature

Resolvers in gql are flexible and can accept parameters in any order:

  • context.Context: Allows passing request-scoped values like authentication data.
  • graphql.ResolveInfo: Provides details about the query execution.
  • Input structs: Used for passing arguments to the resolver.

For example, all of the following resolver signatures are valid:

func (q query) GetUser(ctx context.Context, args UserInput) (*User, error) {}
func (q query) GetUser(info graphql.ResolveInfo, ctx context.Context, args UserInput) (*User, error) {}
func (q query) GetUser(args UserInput) (*User, error) {}

Defining Mutations

You can also define mutations using the same approach:

type mutation struct{}

func (m mutation) CreateUser(ctx context.Context, args User) (*User, error) {
	return &User{ID: "3", FirstName: args.FirstName, LastName: args.LastName}, nil
}

Then include it in your schema:

schema, err := gql.NewSchemaBuilder().
	WithQuery(query{}).
	WithMutation(mutation{}).
	BuildSchema()

Running a GraphQL Server

To integrate with a GraphQL server, use github.com/graphql-go/handler:

import (
	"net/http"
	"github.com/graphql-go/handler"
)

func main() {
	schema, err := gql.NewSchemaBuilder().WithQuery(query{}).BuildSchema()
	if err != nil {
		panic(err)
	}

	h := handler.New(&handler.Config{
		Schema:   schema,
		GraphiQL: true,
	})

	http.Handle("/graphql", h)
	http.ListenAndServe(":8080", nil)
}

graphiql

License

This project is licensed under the MIT License.

About

The Missing GraphQL Schema Builder for Golang

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages