plugin

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Nov 19, 2025 License: MIT Imports: 7 Imported by: 0

README

Schema Generator Plugin for gqlgen

A gqlgen plugin that automatically generates GraphQL schemas from Go structs with special annotations.

FOR THE SCHEMA GENERATION TOOL PLEASE SEE THE MAIN DOCUMENTATION

Installation

go get github.com/pablor21/gqlschemagen/plugin

Opt-in Generation

Structs must have @gqlType() or @gqlInput() directives to be generated:

  • Use @gqlType() to generate a GraphQL type
  • Use @gqlInput() to generate a GraphQL input
  • Structs without these directives are skipped

This gives you precise control over what gets generated from your Go models.

Usage

1. Create a Custom Code Generation Entrypoint

Create a file named generate.go in your project root (same directory as gqlgen.yml):

//go:build ignore
// +build ignore

package main

import (
	"fmt"
	"os"

	"github.com/99designs/gqlgen/api"
	"github.com/99designs/gqlgen/codegen/config"
	"github.com/pablor21/gqlschemagen/plugin"
)

func main() {
	cfg, err := config.LoadConfigFromDefaultLocations()
	if err != nil {
		fmt.Fprintln(os.Stderr, "failed to load config", err.Error())
		os.Exit(2)
	}

	// Create and configure the gqlschemagen plugin
	p := plugin.New()
	p.Packages = []string{
		"./graph/models",  // Scan this directory for Go structs
	}

	// Generate code with the plugin
	err = api.Generate(cfg, api.AddPlugin(p))
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(3)
	}
}
2. Add Go Generate Directive

Add this comment to one of your Go files (e.g., create a tools.go file or add to server.go):

//go:generate go run generate.go

Example tools.go:

//go:build tools
// +build tools

package main

//go:generate go run generate.go

import (
	_ "github.com/99designs/gqlgen"
	_ "github.com/pablor21/gqlschemagen/plugin"
)
3. Configure Your gqlgen.yml

Your gqlgen.yml contains standard gqlgen configuration (NO plugins section):

# Where to find the schema files that will be generated
schema:
  - graph/schema/*.graphql

# Generated code output
exec:
  filename: graph/generated.go
  package: graph

model:
  filename: graph/model/models_gen.go
  package: model

resolver:
  layout: follow-schema
  dir: graph
  package: graph
  filename_template: "{name}.resolvers.go"

# DO NOT add a plugins: section here - it won't work!
4. Run Code Generation
go generate ./...

Or directly:

go run generate.go

This will:

  1. Run your custom generate.go entrypoint
  2. gqlschemagen plugin generates GraphQL schemas from your Go structs
  3. gqlgen continues with normal code generation

Configuration

You can configure the plugin in two ways:

Create a gqlschemagen.yml file in your project root (same directory as gqlgen.yml):

# Packages to scan for Go structs
packages:
  - ./graph/models
  - ./internal/domain

# Generator configuration (all optional)
generator:
  strategy: single                           # "single" or "multiple"
  output: graph/schema/generated.graphql     # Output file or directory
  field_case: camel                          # camel, snake, pascal, original, none
  use_json_tag: true                         # Use json tags for field names
  use_gqlgen_directives: false               # Generate @goModel, @goField directives
  strip_suffix: DTO,Entity,Model             # Strip suffixes from type names
  add_input_suffix: Input                    # Add suffix to input type names
  gen_inputs: true                           # Generate input types automatically

Then load it in your generate.go:

func main() {
    cfg, _ := config.LoadConfigFromDefaultLocations()
    
    // Load plugin configuration from gqlschemagen.yml
    p, err := plugin.LoadConfigFromFile("gqlschemagen.yml")
    if err != nil {
        panic(err)
    }
    
    api.Generate(cfg, api.AddPlugin(p))
}

See the example gqlschemagen.yml for all available options.

Option 2: Programmatic Configuration

Configure directly in generate.go:

p := plugin.New()

// Required: Packages to scan for Go structs with gql annotations
p.Packages = []string{
	"./graph/models",
	"./internal/domain",
}
Advanced Configuration

You can customize the scanner behavior through the plugin's internal config:

package main

import (
	"fmt"
	"os"

	"github.com/99designs/gqlgen/api"
	"github.com/99designs/gqlgen/codegen/config"
	"github.com/pablor21/gqlschemagen/generator"
	"github.com/pablor21/gqlschemagen/plugin"
)

func main() {
	cfg, err := config.LoadConfigFromDefaultLocations()
	if err != nil {
		fmt.Fprintln(os.Stderr, "failed to load config", err.Error())
		os.Exit(2)
	}

	// Create plugin with custom configuration
	genCfg := generator.NewConfig()
	
	// Generation strategy: single file or multiple files
	genCfg.GenStrategy = generator.GenStrategySingle // or GenStrategyMultiple
	
	// Output directory for generated schemas
	genCfg.Output = "graph/schema/generated"
	
	// Field name transformation
	genCfg.FieldCase = "camel" // camel, snake, pascal, original
	
	// Use json tags for field names
	genCfg.UseJSONTag = true
	
	// Generate @goModel and @goField directives
	genCfg.UseGQLGenDirectives = true
	
	// Strip prefixes/suffixes from type names
	genCfg.StripPrefix = []string{"DB", "Pg"}
	genCfg.StripSuffix = []string{"DTO", "Entity", "Model"}
	
	// Create plugin
	p := plugin.New()
	p.Packages = []string{"./graph/models"}
	
	// Note: Currently the plugin uses its default config
	// To use custom config, you may need to modify the plugin
	
	err = api.Generate(cfg, api.AddPlugin(p))
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(3)
	}
}
Configuration Options
Option Type Default Description
Packages []string [] Required. List of package paths to scan for Go structs

The plugin internally creates a generator.Config with these defaults:

  • GenStrategy: single (all types in one file)
  • Output: graph/schema/generated
  • FieldCase: camel
  • UseJSONTag: true
  • UseGQLGenDirectives: true

Examples

Example 1: Single Package
// generate.go
p := plugin.New()
p.Packages = []string{"./graph/models"}
Example 2: Multiple Packages
// generate.go
p := plugin.New()
p.Packages = []string{
	"./graph/models",
	"./internal/domain/entities",
	"./internal/domain/aggregates",
}
Example 3: Monorepo
// generate.go
p := plugin.New()
p.Packages = []string{
	"./services/user/models",
	"./services/product/models",
	"./pkg/common/types",
}

Workflow

Here's what happens when you run go generate ./...:

  1. generate.go executes

    • Loads gqlgen.yml configuration
    • Creates gqlschemagen plugin instance
    • Configures packages to scan
  2. gqlschemagen plugin runs (MutateConfig hook)

    • Scans specified packages for Go structs
    • Finds structs with gql annotations (gql.type, gql.input, etc.)
    • Generates .graphql schema files in the output directory
  3. gqlgen continues

    • Reads the generated schema files
    • Generates resolvers, models, and other code
    • Creates the final GraphQL server code

Annotating Your Structs

In your Go structs, use special comments to define GraphQL types:

package models

// gql.type
// User represents a user in the system
type User struct {
	ID        string    `json:"id"`        // Becomes: id: ID!
	Email     string    `json:"email"`     // Becomes: email: String!
	Name      string    `json:"name"`      // Becomes: name: String!
	CreatedAt time.Time `json:"createdAt"` // Becomes: createdAt: Time!
}

// gql.input
// CreateUserInput is the input for creating a user
type CreateUserInput struct {
	Email string `json:"email"` // email: String!
	Name  string `json:"name"`  // name: String!
}

For more details on annotations, see the main README.

Troubleshooting

Error: "field plugins not found in type config.Config"

This means you tried to add a plugins: section to gqlgen.yml. This doesn't work with gqlgen.

Solution: Remove the plugins: section from gqlgen.yml and configure the plugin in generate.go instead.

Plugin doesn't run

Make sure:

  1. You created generate.go with the correct code
  2. You added //go:generate go run generate.go to a .go file
  3. You're running go generate ./... or go run generate.go
No schemas generated

Check:

  1. p.Packages contains the correct paths to your struct files
  2. Your structs have the proper gql annotations (// gql.type, etc.)
  3. The output directory exists or can be created
Import errors in generate.go

The //go:build ignore comment prevents the file from being part of your normal build. The imports are resolved when you run go run generate.go.

Make sure you have installed the dependencies:

go get github.com/99designs/gqlgen
go get github.com/pablor21/gqlschemagen/plugin
go mod tidy

Complete Example

See the examples/gqlgen-plugin directory for a complete working example.

Why This Approach?

gqlgen's architecture requires plugins to be registered programmatically because:

  1. Plugins can have complex configurations that don't fit in YAML
  2. Plugins may need to modify the gqlgen config before code generation
  3. This gives plugins full control over the generation process

While this requires an extra file (generate.go), it provides maximum flexibility and follows gqlgen's official plugin documentation.

Documentation

Overview

Package plugin provides a gqlgen plugin that automatically generates GraphQL schemas from Go structs with special annotations.

This plugin scans your Go code for structs and generates corresponding GraphQL types, inputs, and mutations based on struct tags and directives. It supports field name transformations, custom directives, and automatic input generation.

Installation

go get github.com/pablor21/gqlschemagen/plugin

Usage

gqlgen plugins must be registered programmatically in a custom code generation entrypoint. Create a file named generate.go in your project root:

//go:build ignore

package main

import (
	"github.com/99designs/gqlgen/api"
	"github.com/99designs/gqlgen/codegen/config"
	"github.com/pablor21/gqlschemagen/plugin"
)

func main() {
	cfg, _ := config.LoadConfigFromDefaultLocations()

	// Load configuration from gqlschemagen.yml (recommended)
	p, err := plugin.LoadConfigFromFile("gqlschemagen.yml")
	if err != nil {
		panic(err)
	}

	// Or configure programmatically
	// p := plugin.New()
	// p.Packages = []string{"./graph/models"}

	// Generate with the plugin
	if err := api.Generate(cfg, api.AddPlugin(p)); err != nil {
		panic(err)
	}
}

Then run: go run generate.go

Configuration

Create a gqlschemagen.yml file (separate from gqlgen.yml to avoid parsing conflicts):

packages:
  - ./graph/models
generator:
  strategy: single
  output: graph/schema/generated.graphql
  field_case: camel
  use_json_tag: true

For detailed documentation and examples, see: https://github.com/pablor21/gqlschemagen/tree/master/plugin

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Plugin

type Plugin struct {

	// Paths to scan for Go structs
	Packages []string `yaml:"packages"`
	// contains filtered or unexported fields
}

Plugin implements the gqlgen plugin interface

func LoadConfigFromFile

func LoadConfigFromFile(filename string) (*Plugin, error)

LoadConfigFromFile loads plugin configuration from a YAML file (typically gqlschemagen.yml) If the file doesn't exist or can't be read, it returns a plugin with default configuration

func New

func New() *Plugin

New creates a new instance of the plugin with default configuration

func (*Plugin) MutateConfig

func (p *Plugin) MutateConfig(cfg *config.Config) error

MutateConfig is called before code generation This is where we generate the GraphQL schemas from Go structs

func (*Plugin) Name

func (p *Plugin) Name() string

Name returns the plugin name

type YAMLConfig

type YAMLConfig struct {
	// Packages to scan for Go structs
	Packages []string `yaml:"packages"`
	// Generator configuration
	Generator *generator.Config `yaml:"generator,omitempty"`
}

YAMLConfig represents the configuration structure in gqlschemagen.yml

Jump to

Keyboard shortcuts

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