This guide details the Schema-First workflow for adding new GraphQL entities, using our helper script to speed up the process.
GraphQL Development Workflow

Step 1: Generate Schema Skeleton

Use the helper script to generate a starting point from your domain model. Command:
# Usage
./scripts/generate-schema.sh <domain-file> > <output-file>

# Example
./scripts/generate-schema.sh internal/modules/product/domain/product.go > internal/modules/product/adapter/inbound/graphql/schema/product.graphql
What it does:
  • Reads your Go struct
  • Converts fields to GraphQL types
  • Adds id, createdAt, updatedAt (if BaseEntity found)
  • Skips sensitive fields like passwordHash automatically
Output Example:
"""
Product type
"""
type Product {
  id: ID!
  createdAt: String!
  updatedAt: String!
  name: String!
  price: Float!
  description: String!
}

Step 2: Edit the Schema

The generated schema is valid but minimal. You need to manually add Queries and Mutations. Open: internal/modules/product/adapter/inbound/graphql/schema/product.graphql Add:
# ... existing type definition ...

extend type Query {
  product(id: ID!): Product
  products(limit: Int, offset: Int): [Product!]!
}

extend type Mutation {
  createProduct(input: CreateProductInput!): Product!
}

input CreateProductInput {
  name: String!
  price: Float!
  description: String
}
Tip: Use extend type so you can have multiple schema files contributing to the root Query and Mutation types.

Step 3: Generate Go Code

Run gqlgen to generate the server code and resolver stubs. Command:
go run github.com/99designs/gqlgen generate
What happens:
  • generated.go is updated (interfaces)
  • models_gen.go is updated (input types)
  • product.resolvers.go is created with stubs

Step 4: Implement Resolvers

Open the newly created resolver file and implement the logic. File: internal/modules/product/adapter/inbound/graphql/product.resolvers.go
// Replace panic with actual implementation
func (r *queryResolver) Product(ctx context.Context, id string) (*domain.Product, error) {
    // Call your existing service
    return r.productService.Get(ctx, id)
}

func (r *mutationResolver) CreateProduct(ctx context.Context, input CreateProductInput) (*domain.Product, error) {
    return r.productService.Create(ctx, ports.CreateProductParams{
        Name:  input.Name,
        Price: input.Price,
    })
}

Summary Checklist

  1. Run Script: ./scripts/generate-schema.sh path/to/domain.go > output.graphql
  2. Edit Schema: Add Query, Mutation, and input types.
  3. CodeGen: go run github.com/99designs/gqlgen generate
  4. Implement: Fill in the functions in *.resolvers.go.
  5. Test: Use Playground at http://localhost:8080/playground.
This workflow gives you the speed of code generation with the architectural purity of Schema-First design!