graphql

package
v1.8.0 Latest Latest
Warning

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

Go to latest
Published: Jun 29, 2025 License: MIT Imports: 16 Imported by: 0

README

GraphQL

Overview

The GraphQL component provides utilities for working with GraphQL in Go applications. It offers a robust server implementation with built-in error handling, request validation, timeout management, and context cancellation handling. This component is designed to work seamlessly with the gqlgen library while adding additional features for production-ready GraphQL APIs.

Features

  • Server Configuration: Configurable query depth, complexity limits, and request timeouts
  • Error Handling: Comprehensive error handling with appropriate error codes and messages
  • Context Awareness: Proper handling of context cancellation and timeouts
  • Request Validation: Validation of GraphQL operations with complexity limits
  • Logging Integration: Seamless integration with the logging component
  • Security Features: Protection against malicious queries with depth and complexity limits
  • Client Disconnect Handling: Graceful handling of client disconnections

Installation

go get github.com/abitofhelp/servicelib/graphql

Quick Start

package main

import (
    "net/http"
    
    "github.com/99designs/gqlgen/graphql/playground"
    "github.com/abitofhelp/servicelib/graphql"
    "github.com/abitofhelp/servicelib/logging"
    "go.uber.org/zap"
)

func main() {
    // Create a logger
    logger, _ := zap.NewProduction()
    contextLogger := logging.NewContextLogger(logger)
    
    // Create a GraphQL server with default configuration
    config := graphql.NewDefaultServerConfig()
    server := graphql.NewServer(
        GeneratedExecutableSchema(),
        contextLogger,
        config,
    )
    
    // Set up routes
    http.Handle("/", playground.Handler("GraphQL Playground", "/query"))
    http.Handle("/query", server)
    
    // Start the server
    http.ListenAndServe(":8080", nil)
}

API Documentation

Core Types
ServerConfig

Configuration for the GraphQL server.

type ServerConfig struct {
    MaxQueryDepth      int
    MaxQueryComplexity int
    RequestTimeout     time.Duration
}
Key Methods
NewDefaultServerConfig

Creates a new server configuration with default values.

func NewDefaultServerConfig() ServerConfig
NewServer

Creates a new GraphQL server with the given schema and configuration.

func NewServer(schema graphql.ExecutableSchema, logger *logging.ContextLogger, cfg ServerConfig) *handler.Server
HandleError

Processes an error and returns an appropriate GraphQL error.

func HandleError(ctx context.Context, err error, operation string, logger *logging.ContextLogger) error

Examples

For complete, runnable examples, see the following directories in the EXAMPLES directory:

  • Basic Server - Shows how to set up a basic GraphQL server
  • Error Handling - Shows how to handle errors in GraphQL resolvers
  • Authentication - Shows how to implement authentication in a GraphQL API
  • File Upload - Shows how to handle file uploads in a GraphQL API

Best Practices

  1. Name Operations: Always name your GraphQL operations for better error reporting and tracing
  2. Set Appropriate Limits: Configure query depth and complexity limits based on your API's needs
  3. Handle Errors Properly: Use the HandleError function to convert domain errors to GraphQL errors
  4. Use Context: Pass context through resolvers to enable proper cancellation and timeouts
  5. Implement Validation: Validate input data before processing to return meaningful errors

Troubleshooting

Common Issues
Query Complexity Exceeded

If you're seeing "query complexity limit exceeded" errors:

  • The client is sending queries that are too complex for your server configuration
  • Consider increasing the MaxQueryComplexity in your ServerConfig
  • Advise clients to simplify their queries or use pagination
Request Timeout

If you're seeing timeout errors:

  • The GraphQL operation is taking longer than the configured RequestTimeout
  • Consider increasing the timeout for complex operations
  • Optimize your resolvers and database queries
  • Implement pagination for large result sets
  • Errors - Error types used by the GraphQL error handler
  • Logging - Logging integration for GraphQL operations
  • Middleware - Middleware for adding request ID and other context values
  • Context - Context utilities for timeout and cancellation handling

Contributing

Contributions to this component are welcome! Please see the Contributing Guide for more information.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Documentation

Overview

Package graphql provides utilities for working with GraphQL.

Package graphql provides utilities for working with GraphQL in Go applications.

This package offers a comprehensive solution for implementing GraphQL APIs, including server configuration, middleware integration, error handling, and authorization directives. It builds on top of the gqlgen library to provide additional features and integrations with other components of the servicelib.

Key features:

  • GraphQL server configuration with sensible defaults
  • Integration with logging, tracing, and metrics
  • Authorization directives for securing GraphQL operations
  • Standardized error handling and conversion
  • Request timeout management
  • Performance monitoring and metrics collection

The package is designed to work seamlessly with other servicelib components, such as auth, logging, telemetry, and middleware.

Example usage for creating a GraphQL server:

// Create a logger
logger := logging.NewContextLogger(zapLogger)

// Create server config with default settings
serverConfig := graphql.NewDefaultServerConfig()

// Create the GraphQL server
server := graphql.NewServer(
    generatedGraphQL.NewExecutableSchema(generatedGraphQL.Config{
        Resolvers: &resolvers.Resolver{},
        Directives: generatedGraphQL.DirectiveRoot{
            IsAuthorized: graphql.IsAuthorizedDirective,
        },
    }),
    logger,
    serverConfig,
)

// Use the server with an HTTP handler
http.Handle("/graphql", server)

Example usage for authorization in resolvers:

func (r *queryResolver) GetUser(ctx context.Context, id string) (*model.User, error) {
    // Check if the user is authorized to view user details
    err := graphql.CheckAuthorization(
        ctx,
        []string{"ADMIN", "USER_MANAGER"},
        []string{"users:read"},
        "user",
        "GetUser",
        r.logger,
    )
    if err != nil {
        return nil, err
    }

    // Proceed with fetching the user
    user, err := r.userService.GetUser(ctx, id)
    if err != nil {
        // Handle and convert errors to GraphQL errors
        return nil, graphql.HandleError(ctx, err, "GetUser", r.logger)
    }

    return user, nil
}

The package also provides utilities for working with GraphQL errors:

// Convert application errors to GraphQL errors
if err != nil {
    return nil, graphql.HandleError(ctx, err, "OperationName", logger)
}

This error handling system automatically maps different error types to appropriate GraphQL errors with the right extensions and codes, while also ensuring that sensitive error details are not exposed to clients.

Package graphql provides utilities for working with GraphQL.

Package graphql provides utilities for working with GraphQL.

Index

Constants

This section is empty.

Variables

View Source
var (
	// AuthorizationCheckDuration measures the duration of authorization checks
	AuthorizationCheckDuration = prometheus.NewHistogram(prometheus.HistogramOpts{
		Name:    "authorization_check_duration_seconds",
		Help:    "Duration of authorization checks in seconds",
		Buckets: prometheus.DefBuckets,
	})

	// AuthorizationFailures counts the number of failed authorization attempts
	AuthorizationFailures = prometheus.NewCounter(prometheus.CounterOpts{
		Name: "authorization_failures_total",
		Help: "Total number of authorization failures",
	})
)

Functions

func CheckAuthorization

func CheckAuthorization(ctx context.Context, allowedRoles []string, requiredScopes []string, resource string, operation string, logger *logging.ContextLogger) error

CheckAuthorization is a helper function to check if the user is authorized to perform an operation It can be used in resolvers to perform custom authorization checks

Parameters:

  • ctx: The context of the request
  • allowedRoles: The roles that are allowed to perform the operation
  • requiredScopes: The scopes that are required to perform the operation (optional)
  • resource: The resource being accessed (optional)
  • operation: The name of the operation being performed
  • logger: A context logger for logging (optional, can be nil)

Returns:

  • An error if not authorized, nil if authorized

func ConvertRolesToStrings

func ConvertRolesToStrings[T fmt.Stringer](roles []T) []string

ConvertRolesToStrings converts a slice of enum roles to a slice of strings This is useful when working with generated enum types for roles

Parameters:

  • roles: A slice of role enums that have a String() method

Returns:

  • A slice of strings representing the roles

func HandleError

func HandleError(ctx context.Context, err error, operation string, logger *logging.ContextLogger) error

HandleError processes an error and returns an appropriate GraphQL error. It logs the error and converts it to a GraphQL error with appropriate extensions. Parameters:

  • ctx: The context containing trace information
  • err: The error to handle
  • operation: The name of the operation that caused the error
  • logger: The logger to use for logging the error

Returns:

  • error: A GraphQL error with appropriate extensions

func IsAuthorizedDirective

func IsAuthorizedDirective(ctx context.Context, obj interface{}, next graphql.Resolver, allowedRoles []string, requiredScopes []string, resource string, logger *logging.ContextLogger) (interface{}, error)

IsAuthorizedDirective implements the @isAuthorized directive for GraphQL It checks if the user has any of the allowed roles and all of the required scopes for the specified resource

Parameters:

  • ctx: The context of the request
  • obj: The object being resolved
  • next: The next resolver in the chain
  • allowedRoles: The roles that are allowed to access this field
  • requiredScopes: The scopes that are required to access this field (optional)
  • resource: The resource being accessed (optional)
  • logger: A context logger for logging (optional, can be nil)

Returns:

  • The result of the next resolver if authorized
  • An error if not authorized

func NewServer

func NewServer(schema graphql.ExecutableSchema, logger *logging.ContextLogger, cfg ServerConfig) *handler.Server

NewServer creates a new GraphQL server with the given schema and configuration

Types

type ServerConfig

type ServerConfig struct {
	MaxQueryDepth      int
	MaxQueryComplexity int
	RequestTimeout     time.Duration
}

ServerConfig contains configuration for the GraphQL server

func DefaultServerConfig added in v1.5.0

func DefaultServerConfig() ServerConfig

DefaultServerConfig returns a default configuration for the GraphQL server. This is an alias for NewDefaultServerConfig for compatibility with the configscan tool.

func NewDefaultServerConfig

func NewDefaultServerConfig() ServerConfig

NewDefaultServerConfig creates a new server configuration with default values

Directories

Path Synopsis
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.

Jump to

Keyboard shortcuts

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