CtrlK
CommunityDocumentationLog inGet started
Tessl Logo

tessl/npm-graphql-yoga

Fully-featured GraphQL Server with focus on easy setup, performance & great developer experience

Overview
Eval results
Files

error-handling.mddocs/

Error Handling

Comprehensive error handling system with masking, GraphQL error creation, and production-ready error processing. Provides secure error reporting while maintaining useful debugging information in development.

Capabilities

Create GraphQL Error

Function to create standardized GraphQL errors with proper extensions and metadata.

/**
 * Creates a GraphQL-compliant error with optional metadata
 * @param message - Error message
 * @param options - Optional error configuration
 * @returns GraphQL error instance
 */
function createGraphQLError(
  message: string,
  options?: {
    nodes?: readonly ASTNode[];
    source?: Source;
    positions?: readonly number[];
    path?: readonly (string | number)[];
    originalError?: Error;
    extensions?: GraphQLErrorExtensions;
  }
): GraphQLError;

Usage Examples:

import { createGraphQLError } from "graphql-yoga";

// Basic error
const error = createGraphQLError("User not found");

// Error with extensions
const authError = createGraphQLError("Authentication required", {
  extensions: {
    code: 'UNAUTHENTICATED',
    http: { status: 401 }
  }
});

// Error with path and original error
const validationError = createGraphQLError("Invalid input", {
  path: ['user', 'email'],
  originalError: new Error('Email format invalid'),
  extensions: {
    field: 'email',
    code: 'VALIDATION_ERROR'
  }
});

// Use in resolvers
const resolvers = {
  Query: {
    user: (_, { id }) => {
      if (!id) {
        throw createGraphQLError("User ID is required", {
          extensions: { code: 'BAD_USER_INPUT' }
        });
      }
      
      const user = findUser(id);
      if (!user) {
        throw createGraphQLError("User not found", {
          extensions: { 
            code: 'NOT_FOUND',
            userId: id
          }
        });
      }
      
      return user;
    }
  }
};

Error Masking

Function to mask sensitive error information for production environments.

/**
 * Masks error details to prevent information leakage
 * @param error - Original error
 * @param message - Fallback error message
 * @param isDev - Whether running in development mode
 * @returns Masked error
 */
function maskError(error: unknown, message: string, isDev?: boolean): Error;

/**
 * Error masking function type
 */
type MaskError = (error: unknown, message: string, isDev?: boolean) => Error;

Usage Examples:

import { maskError } from "graphql-yoga";

// Basic error masking
const maskedError = maskError(
  new Error("Database connection failed with credentials: admin:secret123"),
  "Internal server error",
  false // production mode
);
// Result: Error with message "Internal server error"

// Development mode
const devError = maskError(
  new Error("Database connection failed"),
  "Internal server error",
  true // development mode
);
// Result: Original error preserved for debugging

// Custom masking in server configuration
const yoga = createYoga({
  maskedErrors: {
    errorMessage: 'Something went wrong',
    isDev: process.env.NODE_ENV === 'development',
    maskError: (error, message, isDev) => {
      // Custom masking logic
      if (isDev && error instanceof Error) {
        return error; // Show full error in development
      }
      
      if (error instanceof ValidationError) {
        return new Error('Validation failed'); // Custom message for validation errors
      }
      
      return new Error(message); // Default masked message
    }
  }
});

Error Handling

Comprehensive error processing function that handles various error types and formats.

/**
 * Processes and formats various error types into GraphQL errors
 * @param error - Error to handle
 * @param maskedErrorsOpts - Error masking configuration
 * @param logger - Logger instance
 * @returns Array of GraphQL errors
 */
function handleError(
  error: unknown,
  maskedErrorsOpts: YogaMaskedErrorOpts | null,
  logger: YogaLogger
): GraphQLError[];

/**
 * Error masking configuration
 */
interface YogaMaskedErrorOpts {
  /** Custom error masking function */
  maskError: MaskError;
  /** Default error message for masked errors */
  errorMessage: string;
  /** Whether running in development mode */
  isDev?: boolean;
}

Usage Examples:

import { handleError } from "graphql-yoga";

// Error handling in custom plugin
const errorHandlingPlugin: Plugin = {
  onResultProcess({ result, setResult }) {
    if ('errors' in result && result.errors) {
      const processedErrors = result.errors.map(error => 
        handleError(error, maskedErrorsOpts, logger)
      ).flat();
      
      setResult({
        ...result,
        errors: processedErrors
      });
    }
  }
};

// Custom error handling configuration
const maskedErrorsOpts: YogaMaskedErrorOpts = {
  errorMessage: 'An unexpected error occurred',
  isDev: process.env.NODE_ENV === 'development',
  maskError: (error, message, isDev) => {
    if (isDev) {
      console.error('Development error:', error);
      return error instanceof Error ? error : new Error(String(error));
    }
    
    // Log original error but return masked message
    if (error instanceof Error) {
      console.error('Production error masked:', error.message);
    }
    
    return new Error(message);
  }
};

Error Type Guards

Utility functions for identifying and working with different error types.

/**
 * Check if value is a GraphQL error
 * @param val - Value to check
 * @returns Whether value is GraphQL error
 */
function isGraphQLError(val: unknown): val is GraphQLError;

/**
 * Check if value is an original GraphQL error (not wrapped)
 * @param val - Value to check
 * @returns Whether value is original GraphQL error
 */
function isOriginalGraphQLError(
  val: unknown
): val is GraphQLError & { originalError: GraphQLError };

/**
 * Check if object is an array of GraphQL errors
 * @param obj - Object to check
 * @returns Whether object is GraphQL error array
 */
function areGraphQLErrors(obj: unknown): obj is readonly GraphQLError[];

Usage Examples:

import { isGraphQLError, isOriginalGraphQLError, areGraphQLErrors } from "graphql-yoga";

// Error type checking
function processError(error: unknown) {
  if (isGraphQLError(error)) {
    console.log('GraphQL error:', error.message);
    console.log('Extensions:', error.extensions);
    
    if (isOriginalGraphQLError(error)) {
      console.log('Original error:', error.originalError);
    }
  } else {
    console.log('Non-GraphQL error:', error);
  }
}

// Processing error arrays
function processErrors(errors: unknown) {
  if (areGraphQLErrors(errors)) {
    errors.forEach((error, index) => {
      console.log(`Error ${index}:`, error.message);
    });
  }
}

// Use in resolver error handling
const resolvers = {
  Query: {
    sensitiveData: async (_, __, context) => {
      try {
        return await fetchSensitiveData(context.userId);
      } catch (error) {
        if (isGraphQLError(error)) {
          throw error; // Re-throw GraphQL errors as-is
        }
        
        // Convert other errors to GraphQL errors
        throw createGraphQLError("Failed to fetch data", {
          originalError: error instanceof Error ? error : new Error(String(error)),
          extensions: { code: 'FETCH_ERROR' }
        });
      }
    }
  }
};

Response Error Handling

Function to generate HTTP response configuration based on GraphQL errors.

/**
 * Generates HTTP response configuration based on GraphQL errors
 * @param result - GraphQL execution result
 * @param headers - Additional headers to include
 * @param isApplicationJson - Whether response is JSON
 * @returns Response configuration with status and headers
 */
function getResponseInitByRespectingErrors(
  result: ResultProcessorInput,
  headers?: Record<string, string>,
  isApplicationJson?: boolean
): {
  status: number;
  headers: Record<string, string>;
};

Usage Examples:

import { getResponseInitByRespectingErrors } from "graphql-yoga";

// Custom result processor using error-aware response
const customProcessor: ResultProcessor = (result, fetchAPI) => {
  const responseInit = getResponseInitByRespectingErrors(result, {
    'X-Custom-Header': 'value'
  }, true);
  
  return new fetchAPI.Response(
    JSON.stringify(result),
    {
      status: responseInit.status,
      headers: {
        'Content-Type': 'application/json',
        ...responseInit.headers
      }
    }
  );
};

// Error-aware response in plugin
const responsePlugin: Plugin = {
  onResultProcess({ result, setResultProcessor }) {
    setResultProcessor((result, fetchAPI) => {
      const { status, headers } = getResponseInitByRespectingErrors(result);
      
      // Add custom error tracking
      if (status >= 400) {
        headers['X-Error-Tracked'] = 'true';
        logError(result);
      }
      
      return new fetchAPI.Response(JSON.stringify(result), {
        status,
        headers: {
          'Content-Type': 'application/json',
          ...headers
        }
      });
    }, 'application/json');
  }
};

GraphQL Error Extensions

Extended error information for HTTP-specific and Yoga-specific metadata.

/**
 * GraphQL error extensions with HTTP metadata
 */
interface GraphQLHTTPExtensions {
  /** Whether error follows GraphQL spec */
  spec?: boolean;
  /** HTTP status code */
  status?: number;
  /** HTTP headers to set */
  headers?: Record<string, string>;
}

/**
 * Extended GraphQL error extensions
 */
declare module 'graphql' {
  interface GraphQLErrorExtensions {
    /** HTTP-specific extensions */
    http?: GraphQLHTTPExtensions;
    /** Whether error was unexpected */
    unexpected?: boolean;
  }
}

Usage Examples:

// Error with HTTP extensions
const httpError = createGraphQLError("Unauthorized", {
  extensions: {
    code: 'UNAUTHORIZED',
    http: {
      status: 401,
      headers: {
        'WWW-Authenticate': 'Bearer'
      }
    }
  }
});

// Error with custom extensions
const businessError = createGraphQLError("Insufficient funds", {
  extensions: {
    code: 'BUSINESS_LOGIC_ERROR',
    category: 'payment',
    retryable: false,
    http: {
      status: 422
    }
  }
});

// Use in resolvers
const resolvers = {
  Mutation: {
    processPayment: async (_, { amount }, context) => {
      if (!context.user) {
        throw createGraphQLError("Authentication required", {
          extensions: {
            code: 'UNAUTHENTICATED',
            http: { status: 401 }
          }
        });
      }
      
      if (amount <= 0) {
        throw createGraphQLError("Invalid amount", {
          extensions: {
            code: 'VALIDATION_ERROR',
            field: 'amount',
            http: { status: 400 }
          }
        });
      }
      
      try {
        return await processPayment(amount, context.user);
      } catch (error) {
        throw createGraphQLError("Payment processing failed", {
          originalError: error,
          extensions: {
            code: 'PAYMENT_ERROR',
            http: { status: 502 }
          }
        });
      }
    }
  }
};
tessl i tessl/npm-graphql-yoga@4.0.0

docs

built-in-plugins.md

error-handling.md

index.md

plugin-system.md

schema-integration.md

server-configuration.md

subscription-support.md

utility-functions.md

tile.json