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

plugin-system.mddocs/

Plugin System

Comprehensive plugin system extending Envelop with Yoga-specific hooks for request processing, result handling, and server lifecycle management. Enables extensible GraphQL server functionality through composable plugins.

Capabilities

Plugin Interface

Main plugin interface that extends Envelop plugins with Yoga-specific functionality.

/**
 * Yoga plugin interface extending Envelop and server adapter plugins
 */
interface Plugin<
  PluginContext extends Record<string, any> = {},
  TServerContext extends Record<string, any> = {},
  TUserContext = {}
> extends EnvelopPlugin<YogaInitialContext & PluginContext>, ServerAdapterPlugin<TServerContext> {
  /** Called when Yoga server initializes */
  onYogaInit?: OnYogaInitHook<TServerContext>;
  /** Called during HTTP request parsing */
  onRequestParse?: OnRequestParseHook<TServerContext>;
  /** Called before GraphQL execution with parameters */
  onParams?: OnParamsHook;
  /** Called during result processing */
  onResultProcess?: OnResultProcess;
  /** Called before GraphQL execution */
  onExecute?: OnExecuteHook<YogaInitialContext & PluginContext & TUserContext>;
  /** Called before GraphQL subscription */
  onSubscribe?: OnSubscribeHook<YogaInitialContext & PluginContext & TUserContext>;
}

Usage Examples:

import { Plugin } from "graphql-yoga";

// Basic plugin
const myPlugin: Plugin = {
  onYogaInit({ yoga }) {
    console.log(`Yoga server initialized with endpoint: ${yoga.graphqlEndpoint}`);
  },
  onRequestParse({ request, url }) {
    console.log(`Processing request to: ${url.pathname}`);
  }
};

// Plugin with context typing
const contextPlugin: Plugin<{ startTime: number }> = {
  onParams({ setParams, params }) {
    setParams({
      ...params,
      extensions: {
        ...params.extensions,
        startTime: Date.now()
      }
    });
  }
};

// Use plugins
const yoga = createYoga({
  plugins: [myPlugin, contextPlugin]
});

Yoga-Specific Hooks

Hooks that are unique to Yoga for server lifecycle and request processing.

/**
 * Hook called when Yoga server initializes
 */
type OnYogaInitHook<TServerContext extends Record<string, any>> = (
  payload: OnYogaInitEventPayload<TServerContext>
) => void;

interface OnYogaInitEventPayload<TServerContext extends Record<string, any>> {
  yoga: YogaServer<TServerContext, any>;
}

/**
 * Hook called during HTTP request parsing
 */
type OnRequestParseHook<TServerContext> = (
  payload: OnRequestParseEventPayload<TServerContext>
) => PromiseOrValue<void | OnRequestParseHookResult>;

interface OnRequestParseEventPayload<TServerContext> {
  request: Request;
  url: URL;
  requestParser: RequestParser | undefined;
  serverContext: TServerContext;
  setRequestParser: (parser: RequestParser) => void;
}

type OnRequestParseHookResult = {
  onRequestParseDone?: OnRequestParseDoneHook;
};

Usage Examples:

// Server initialization hook
const initPlugin: Plugin = {
  onYogaInit({ yoga }) {
    // Access server instance
    console.log(`Server ID: ${yoga.id}`);
    console.log(`GraphQL endpoint: ${yoga.graphqlEndpoint}`);
    
    // Set up server-wide resources
    setupMetrics(yoga);
  }
};

// Request parsing hook
const parsePlugin: Plugin = {
  onRequestParse({ request, url, setRequestParser }) {
    // Custom request parser for specific content types
    if (request.headers.get('content-type')?.includes('application/custom')) {
      setRequestParser(async (req) => {
        const body = await req.text();
        return parseCustomFormat(body);
      });
    }
  }
};

Parameters and Result Processing Hooks

Hooks for intercepting and modifying GraphQL parameters and execution results.

/**
 * Hook called before GraphQL execution with parameters
 */
type OnParamsHook = (payload: OnParamsEventPayload) => PromiseOrValue<void>;

interface OnParamsEventPayload {
  params: GraphQLParams;
  request: Request;
  setParams: (params: GraphQLParams) => void;
  setResult: (result: ExecutionResult) => void;
  fetchAPI: FetchAPI;
}

/**
 * Hook called during result processing
 */
type OnResultProcess = (payload: OnResultProcessEventPayload) => PromiseOrValue<void>;

interface OnResultProcessEventPayload {
  request: Request;
  result: ResultProcessorInput;
  setResult: (result: ResultProcessorInput) => void;
  resultProcessor?: ResultProcessor;
  acceptableMediaTypes: string[];
  setResultProcessor: (resultProcessor: ResultProcessor, acceptedMediaType: string) => void;
}

Usage Examples:

// Parameter modification plugin
const paramsPlugin: Plugin = {
  onParams({ params, setParams, request }) {
    // Add request metadata to extensions
    setParams({
      ...params,
      extensions: {
        ...params.extensions,
        requestId: request.headers.get('x-request-id'),
        timestamp: Date.now()
      }
    });
  }
};

// Result processing plugin
const resultPlugin: Plugin = {
  onResultProcess({ result, setResult, request }) {
    // Add execution metadata to result
    if ('data' in result || 'errors' in result) {
      setResult({
        ...result,
        extensions: {
          ...result.extensions,
          executedAt: new Date().toISOString(),
          requestId: request.headers.get('x-request-id')
        }
      });
    }
  }
};

Request Parser Types

Types for custom request parsers that extract GraphQL parameters from HTTP requests.

/**
 * Function type for parsing HTTP requests to GraphQL parameters
 */
type RequestParser = (
  request: Request
) => PromiseOrValue<GraphQLParams> | PromiseOrValue<GraphQLParams[]>;

/**
 * Hook called after request parsing is done
 */
type OnRequestParseDoneHook = (
  payload: OnRequestParseDoneEventPayload
) => PromiseOrValue<void>;

interface OnRequestParseDoneEventPayload {
  requestParserResult: GraphQLParams | GraphQLParams[];
  setRequestParserResult: (params: GraphQLParams | GraphQLParams[]) => void;
}

Usage Examples:

// Custom request parser
const customParser: RequestParser = async (request) => {
  const contentType = request.headers.get('content-type');
  
  if (contentType?.includes('application/graphql')) {
    // Parse GraphQL query directly from body
    const query = await request.text();
    return { query };
  }
  
  if (contentType?.includes('application/json')) {
    const body = await request.json();
    return body;
  }
  
  throw new Error('Unsupported content type');
};

// Plugin using custom parser
const customParserPlugin: Plugin = {
  onRequestParse({ request, setRequestParser }) {
    if (request.url.includes('/custom-graphql')) {
      setRequestParser(customParser);
    }
  }
};

Result Processor Types

Types for custom result processors that format GraphQL execution results into HTTP responses.

/**
 * Function type for processing GraphQL results into HTTP responses
 */
type ResultProcessor = (
  result: ResultProcessorInput,
  fetchAPI: FetchAPI,
  acceptedMediaType: string
) => PromiseOrValue<Response>;

/**
 * GraphQL execution result with optional serialization
 */
type ExecutionResultWithSerializer<TData = any, TExtensions = any> = ExecutionResult<
  TData,
  TExtensions
> & {
  stringify?: (result: ExecutionResult<TData, TExtensions>) => string;
};

/**
 * Input type for result processors
 */
type ResultProcessorInput =
  | MaybeArray<ExecutionResultWithSerializer>
  | AsyncIterable<ExecutionResultWithSerializer<any, { http?: GraphQLHTTPExtensions }>>;

Usage Examples:

// Custom result processor
const xmlProcessor: ResultProcessor = (result, fetchAPI, acceptedMediaType) => {
  if (acceptedMediaType.includes('application/xml')) {
    const xmlResult = convertToXML(result);
    return new fetchAPI.Response(xmlResult, {
      headers: { 'Content-Type': 'application/xml' }
    });
  }
  
  throw new Error('Unsupported media type');
};

// Plugin using custom result processor
const xmlPlugin: Plugin = {
  onResultProcess({ request, setResultProcessor }) {
    const acceptHeader = request.headers.get('accept');
    if (acceptHeader?.includes('application/xml')) {
      setResultProcessor(xmlProcessor, 'application/xml');
    }
  }
};

Plugin Composition

Patterns for composing and organizing multiple plugins.

/**
 * Plugin array type for server configuration
 */
type PluginArray = Array<
  Plugin<any> | Plugin | {}
>;

Usage Examples:

// Plugin composition
const authPlugin: Plugin = {
  onParams({ params, request, setResult }) {
    const token = request.headers.get('authorization');
    if (!token) {
      setResult({
        errors: [new GraphQLError('Authentication required')]
      });
    }
  }
};

const metricsPlugin: Plugin = {
  onYogaInit({ yoga }) {
    setupMetrics(yoga);
  },
  onParams({ params }) {
    incrementOperationCount(params.operationName);
  }
};

const loggingPlugin: Plugin = {
  onParams({ params, request }) {
    console.log(`GraphQL operation: ${params.operationName}`);
  },
  onResultProcess({ result }) {
    console.log(`Result processed: ${JSON.stringify(result)}`);
  }
};

// Use multiple plugins
const yoga = createYoga({
  plugins: [
    authPlugin,
    metricsPlugin,
    loggingPlugin,
    // Third-party plugins
    useDepthLimit(10),
    useDisableIntrospection()
  ]
});
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