Skip to content

Conversation

@coolwednesday
Copy link
Member

@coolwednesday coolwednesday commented Feb 2, 2026

Add Native GraphQL Support to GoFr

Overview

This PR introduces native GraphQL support to GoFr with a code-first approach that eliminates the need for schema files or code generation. Developers can now build GraphQL APIs using the same familiar patterns as REST handlers, with automatic schema generation from Go types.

✨ Key Features

1. Code-First Philosophy

  • No schema files required - GraphQL schema is automatically generated from Go structs and function signatures
  • Automatic type discovery - Reflection-based engine discovers fields, arguments, and return types at startup
  • JSON tag support - Uses existing json tags for field naming, maintaining consistency with REST APIs

2. Developer Experience

  • Context Parity - GraphQL resolvers receive *gofr.Context, providing seamless access to logger, databases, HTTP clients, etc.
  • Declarative Arguments - Function signatures define GraphQL arguments automatically:
    type GetUserArgs struct {
        ID int `json:"id"`
    }
    
    app.GraphQLQuery("getUser", func(c *gofr.Context, args GetUserArgs) (User, error) {
        // GoFr automatically maps GraphQL arguments to the args struct
        return fetchUser(args.ID), nil
    })
  • Interactive Playground - Built-in GraphQL Playground UI at /graphql/ui (auto-disabled in production)

3. Architecture

  • Single Endpoint - All GraphQL operations served at /graphql (industry standard)
  • Middleware Reusability - Full compatibility with existing GoFr HTTP middlewares (CORS, Auth, Logging, Metrics, Tracer)
  • Unified Schema - Queries and mutations aggregated into a single introspectable schema
  • Built-in Health - gofr query field provides health check via GraphQL

4. Performance

  • Startup Reflection - Schema built once during application initialization
  • Zero Runtime Overhead - No reflection during request processing (only at startup)
  • Direct Response Writing - Bypasses GoFr's REST response layer to avoid redundant serialization

🔧 API

Registration

app := gofr.New()

// Register a Query
app.GraphQLQuery("user", func(c *gofr.Context) (User, error) {
    return User{ID: 1, Name: "Alice"}, nil
})

// Register a Mutation
app.GraphQLMutation("createUser", func(c *gofr.Context, args CreateUserArgs) (User, error) {
    return createUser(args), nil
})

app.Run()

Endpoints

  • POST /graphql - GraphQL endpoint (always available)
  • GET /graphql/ui - Interactive Playground (disabled when APP_ENV=production)

🧪 Testing

Integration Tests

  • Full end-to-end tests in examples/using-graphql/main_test.go
  • Tests for all query types and Playground UI
  • Production environment test (UI not registered)

🔒 Security

  • Production Safety - Playground UI automatically disabled when APP_ENV=production
  • Middleware Support - Auth, CORS, and other security middlewares work seamlessly
  • Error Handling - GraphQL errors returned in standard format without exposing internals

🎓 Example Usage

package main

import "gofr.dev/pkg/gofr"

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
    Role string `json:"role"`
}

type GetUserArgs struct {
    ID int `json:"id"`
}

func main() {
    app := gofr.New()

    // Simple query
    app.GraphQLQuery("hello", func(c *gofr.Context) (string, error) {
        return "Hello GraphQL!", nil
    })

    // Query with arguments
    app.GraphQLQuery("user", func(c *gofr.Context, args GetUserArgs) (User, error) {
        return User{ID: args.ID, Name: "Alice", Role: "Admin"}, nil
    })

    // Mutation
    app.GraphQLMutation("createUser", func(c *gofr.Context, args User) (User, error) {
        // Save user to database
        return args, nil
    })

    app.Run()
}

GraphQL Query:

query {
  user(id: 1) {
    id
    name
    role
  }
}

Checklist:

  • I have formatted my code using goimport and golangci-lint.
  • All new code is covered by unit tests.
  • This PR does not decrease the overall code coverage.
  • I have reviewed the code comments and documentation for clarity.

Thank you for your contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GraphQL support

1 participant