or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

error-handling.mdhttp-integration.mdindex.mdplugins.mdserver-lifecycle.mdtypes.md
tile.json

types.mddocs/

Core Types

Essential type definitions for server configuration, request/response handling, context management, and plugin development in Apollo Server.

Capabilities

Configuration Types

Core types for configuring Apollo Server instances with different schema sources.

/**
 * Apollo Server configuration options
 * Union of schema-based, typeDefs-based, or gateway-based configurations
 */
type ApolloServerOptions<TContext extends BaseContext> = 
  | ApolloServerOptionsWithSchema<TContext>
  | ApolloServerOptionsWithTypeDefs<TContext> 
  | ApolloServerOptionsWithGateway<TContext>;

/**
 * Configuration with pre-built GraphQL schema
 */
interface ApolloServerOptionsWithSchema<TContext extends BaseContext> {
  /** Pre-built GraphQL schema */
  schema: GraphQLSchema;
  /** Plugin array for extending functionality */
  plugins?: ApolloServerPlugin<TContext>[];
  /** Custom error formatting function */
  formatError?: (formattedError: GraphQLFormattedError, error: unknown) => GraphQLFormattedError;
  /** Cache implementation or 'bounded' for default LRU cache */
  cache?: KeyValueCache<string> | 'bounded';
  /** Logger implementation */
  logger?: Logger;
  /** Enable/disable GraphQL introspection queries */
  introspection?: boolean;
  /** CSRF prevention configuration */
  csrfPrevention?: CSRFPreventionOptions | boolean;
  /** Include stack traces in error responses (default: false in production) */
  includeStacktraceInErrorResponses?: boolean;
  /** Custom GraphQL field resolver */
  fieldResolver?: GraphQLFieldResolver<any, TContext>;
  /** Persisted queries configuration */
  persistedQueries?: PersistedQueryOptions;
  /** Apollo Studio registry configuration */
  apollo?: ApolloConfigInput;
  /** Node environment override */
  nodeEnv?: string;
}

/**
 * Configuration with GraphQL type definitions and resolvers
 */
interface ApolloServerOptionsWithTypeDefs<TContext extends BaseContext> 
  extends Omit<ApolloServerOptionsWithSchema<TContext>, 'schema'> {
  /** GraphQL type definitions (string, DocumentNode, or array) */
  typeDefs: TypeSource;
  /** GraphQL resolvers object */
  resolvers?: IResolvers;
}

/**
 * Configuration with Apollo Gateway for federation
 */
interface ApolloServerOptionsWithGateway<TContext extends BaseContext> 
  extends Omit<ApolloServerOptionsWithSchema<TContext>, 'schema'> {
  /** Apollo Gateway instance for federation */
  gateway: GatewayInterface;
}

Apollo Configuration

Types for connecting Apollo Server to Apollo Studio registry and services.

/**
 * Apollo Studio configuration input
 */
interface ApolloConfigInput {
  /** Apollo Studio API key */
  key?: string;
  /** Graph reference (graphId@variant) */
  graphRef?: string;
  /** Graph ID (alternative to graphRef) */
  graphId?: string;
  /** Graph variant (alternative to graphRef, default: 'current') */
  graphVariant?: string;
}

/**
 * Processed Apollo configuration with computed values
 */
interface ApolloConfig {
  /** Apollo Studio API key */
  key?: string;
  /** Hash of the API key for logging */
  keyHash?: string;
  /** Graph reference (graphId@variant) */
  graphRef?: string;
}

Request and Response Types

Types for GraphQL requests, responses, and HTTP-specific handling.

/**
 * GraphQL operation request
 */
interface GraphQLRequest<TVariables = VariableValues> {
  /** GraphQL query string or parsed DocumentNode */
  query?: string | DocumentNode;
  /** Operation name for multi-operation documents */
  operationName?: string;
  /** Variables object for the operation */
  variables?: TVariables;
  /** Extensions object for additional metadata */
  extensions?: Record<string, any>;
  /** HTTP-specific request information */
  http?: HTTPGraphQLHead;
}

/**
 * GraphQL operation response
 */
interface GraphQLResponse<TData = Record<string, unknown>> {
  /** HTTP response metadata */
  http: HTTPGraphQLHead;
  /** Response body (single result or incremental delivery) */
  body: GraphQLResponseBody<TData>;
}

/**
 * GraphQL response body - single result or incremental delivery
 */
type GraphQLResponseBody<TData = Record<string, unknown>> = 
  | { kind: 'single'; singleResult: FormattedExecutionResult<TData> }
  | { 
      kind: 'incremental'; 
      initialResult: GraphQLExperimentalFormattedInitialIncrementalExecutionResult<TData>;
      subsequentResults: AsyncIterator<GraphQLExperimentalFormattedSubsequentIncrementalExecutionResult<TData>>;
    };

/**
 * Variable values type for GraphQL operations
 */
type VariableValues = { [name: string]: any };

/**
 * HTTP-specific GraphQL request information
 */
interface HTTPGraphQLRequest {
  /** HTTP method (GET, POST, etc.) */
  method: string;
  /** Request headers */
  headers: HeaderMap;
  /** URL search parameters */
  search: string;
  /** Request body */
  body: unknown;
}

/**
 * HTTP response headers and status
 */
interface HTTPGraphQLHead {
  /** HTTP status code */
  status?: number;
  /** Response headers */
  headers: HeaderMap;
}

/**
 * Complete HTTP GraphQL response
 */
interface HTTPGraphQLResponse {
  /** HTTP status code */
  status?: number;
  /** Response headers */
  headers: HeaderMap;
  /** Response body (complete string or chunked iterator) */
  body: HTTPGraphQLResponseBody;
}

/**
 * HTTP response body - complete or streaming
 */
type HTTPGraphQLResponseBody = 
  | { kind: 'complete'; string: string }
  | { kind: 'chunked'; asyncIterator: AsyncIterator<string> };

Context Types

Types for managing GraphQL execution context across different integration scenarios.

/**
 * Base context type that all GraphQL contexts must extend
 */
type BaseContext = {};

/**
 * Context function type for integration authors
 * @template TIntegrationSpecificArgs - Arguments provided by the integration
 * @template TContext - The context type to return
 */
type ContextFunction<
  TIntegrationSpecificArgs extends ReadonlyArray<any>,
  TContext extends BaseContext
> = (...args: TIntegrationSpecificArgs) => Promise<TContext>;

/**
 * Internal context thunk type used by Apollo Server
 */
type ContextThunk<TContext extends BaseContext> = () => Promise<TContext>;

/**
 * Options for executeOperation method
 */
interface ExecuteOperationOptions<TContext extends BaseContext> {
  /** Context value for the operation */
  contextValue?: TContext;
}

Plugin System Types

Types for the Apollo Server plugin system and request lifecycle hooks.

/**
 * Main plugin interface for extending Apollo Server functionality
 */
interface ApolloServerPlugin<TContext extends BaseContext> {
  /** Called when server starts up */
  serverWillStart?(service: GraphQLServerContext): Promise<GraphQLServerListener | void>;
  /** Called for each GraphQL request */
  requestDidStart?(requestContext: GraphQLRequestContext<TContext>): Promise<GraphQLRequestListener<TContext> | void>;
  /** Called for unexpected errors during request processing */
  unexpectedErrorProcessingRequest?(requestContext: GraphQLRequestContext<TContext>, error: Error): Promise<void>;
}

/**
 * Server-level context available to plugins
 */
interface GraphQLServerContext {
  /** Logger instance */
  logger: Logger;
  /** Cache instance */
  cache: KeyValueCache<string>;
  /** GraphQL schema */
  schema: GraphQLSchema;
  /** Apollo Studio configuration */
  apollo: ApolloConfig;
  /** Whether server started in background mode */
  startedInBackground: boolean;
}

/**
 * Schema-specific context for plugins
 */
interface GraphQLSchemaContext {
  /** API schema (processed for federation) */
  apiSchema: GraphQLSchema;
  /** Core supergraph SDL for federation */
  coreSupergraphSdl?: string;
}

/**
 * Request-level plugin hooks
 */
interface GraphQLRequestListener<TContext extends BaseContext> {
  /** Called after request source is resolved */
  didResolveSource?(requestContext: GraphQLRequestContextDidResolveSource<TContext>): Promise<void>;
  /** Called before parsing starts */
  parsingDidStart?(requestContext: GraphQLRequestContextParsingDidStart<TContext>): Promise<GraphQLRequestListenerParsingDidEnd | void>;
  /** Called before validation starts */
  validationDidStart?(requestContext: GraphQLRequestContextValidationDidStart<TContext>): Promise<GraphQLRequestListenerValidationDidEnd | void>;
  /** Called after operation is resolved */
  didResolveOperation?(requestContext: GraphQLRequestContextDidResolveOperation<TContext>): Promise<void>;
  /** Called before execution starts */
  executionDidStart?(requestContext: GraphQLRequestContextExecutionDidStart<TContext>): Promise<GraphQLRequestExecutionListener<TContext> | void>;
  /** Called when errors are encountered */
  didEncounterErrors?(requestContext: GraphQLRequestContextDidEncounterErrors<TContext>): Promise<void>;
  /** Called before sending response */
  willSendResponse?(requestContext: GraphQLRequestContextWillSendResponse<TContext>): Promise<void>;
}

/**
 * Core request context passed to plugin hooks
 */
interface GraphQLRequestContext<TContext extends BaseContext> {
  /** Unique request ID */
  requestId?: string;
  /** Logger scoped to this request */
  logger: Logger;
  /** Cache instance */
  cache: KeyValueCache<string>;
  /** GraphQL schema being used */
  schema: GraphQLSchema;
  /** Apollo Studio configuration */
  apollo: ApolloConfig;
  /** GraphQL request object */
  request: GraphQLRequest;
  /** GraphQL response object */
  response?: GraphQLResponse;
  /** GraphQL context value */
  contextValue: TContext;
  /** Request metrics and feature flags */
  metrics: GraphQLRequestMetrics;
  /** Operation name (if resolved) */
  operationName?: string;
  /** Operation AST (if parsed) */
  operation?: OperationDefinitionNode;
  /** Validation errors (if any) */
  errors?: ReadonlyArray<GraphQLError>;
}

/**
 * Request metrics and feature usage tracking
 */
interface GraphQLRequestMetrics {
  /** Whether to capture execution traces */
  captureTraces?: boolean;
  /** Persisted query cache hit/miss status */
  persistedQueryHit?: boolean;
  /** Response cache hit/miss status */
  responseCacheHit?: boolean;
  /** Forbid usage reporting for this request */
  forbidUsageReporting?: boolean;
  /** Start time of request processing */
  startedAt: Date;
  /** Parsed query string hash */
  queryHash?: string;
}

Cache and Storage Types

Types for caching, document storage, and persisted queries.

/**
 * Document store for caching parsed GraphQL documents
 */
type DocumentStore = KeyValueCache<DocumentNode>;

/**
 * Persisted queries configuration
 */
interface PersistedQueryOptions {
  /** Cache implementation for storing persisted queries */
  cache?: KeyValueCache<string>;
  /** Time-to-live for persisted queries in seconds */
  ttl?: number;
}

/**
 * CSRF prevention configuration
 */
interface CSRFPreventionOptions {
  /** Required request headers for CSRF protection */
  requestHeaders?: string[];
}

/**
 * Landing page configuration
 */
interface LandingPage {
  /** HTML content (string or async function) */
  html: string | (() => Promise<string>);
}

Incremental Delivery Types

Types for experimental GraphQL @defer and @stream support.

/**
 * Initial result for incremental delivery operations
 */
interface GraphQLExperimentalFormattedInitialIncrementalExecutionResult<
  TData = Record<string, any>,
  TExtensions = Record<string, any>
> extends FormattedExecutionResult<TData, TExtensions> {
  /** Whether more results will follow */
  hasNext: boolean;
  /** Initial incremental results */
  incremental?: ReadonlyArray<GraphQLExperimentalFormattedIncrementalResult<TData, TExtensions>>;
}

/**
 * Subsequent results for incremental delivery
 */
interface GraphQLExperimentalFormattedSubsequentIncrementalExecutionResult<
  TData = Record<string, any>,
  TExtensions = Record<string, any>
> {
  /** Whether more results will follow */
  hasNext: boolean;
  /** Incremental results */
  incremental?: ReadonlyArray<GraphQLExperimentalFormattedIncrementalResult<TData, TExtensions>>;
  /** Extensions object */
  extensions?: TExtensions;
}

/**
 * Union of defer and stream incremental results
 */
type GraphQLExperimentalFormattedIncrementalResult<
  TData = Record<string, any>,
  TExtensions = Record<string, any>
> = 
  | GraphQLExperimentalFormattedIncrementalDeferResult<TData, TExtensions>
  | GraphQLExperimentalFormattedIncrementalStreamResult<TData, TExtensions>;

/**
 * Defer-specific incremental result
 */
interface GraphQLExperimentalFormattedIncrementalDeferResult<
  TData = Record<string, any>,
  TExtensions = Record<string, any>
> extends FormattedExecutionResult<TData, TExtensions> {
  /** Path to the deferred field */
  path?: ReadonlyArray<string | number>;
  /** Label for the deferred fragment */
  label?: string;
}

/**
 * Stream-specific incremental result
 */
interface GraphQLExperimentalFormattedIncrementalStreamResult<
  TData = Record<string, any>,
  TExtensions = Record<string, any>
> {
  /** Errors that occurred during streaming */
  errors?: ReadonlyArray<GraphQLFormattedError>;
  /** Stream items */
  items?: ReadonlyArray<TData>;
  /** Path to the streamed field */
  path?: ReadonlyArray<string | number>;
  /** Label for the streamed field */
  label?: string;
  /** Extensions object */
  extensions?: TExtensions;
}

Usage Examples

Type-Safe Server Configuration

import { ApolloServer, BaseContext } from "@apollo/server";
import type { ApolloServerOptions } from "@apollo/server";

// Define custom context type
interface MyContext extends BaseContext {
  user?: {
    id: string;
    email: string;
    roles: string[];
  };
  dataSources: {
    userAPI: UserAPI;
    postAPI: PostAPI;
  };
}

// Type-safe server configuration
const config: ApolloServerOptions<MyContext> = {
  typeDefs: `
    type Query {
      me: User
      posts: [Post!]!
    }
    type User {
      id: ID!
      email: String!
    }
    type Post {
      id: ID!
      title: String!
      authorId: ID!
    }
  `,
  resolvers: {
    Query: {
      me: (_, __, context) => {
        // context is properly typed as MyContext
        return context.user ? context.dataSources.userAPI.findById(context.user.id) : null;
      },
      posts: (_, __, context) => {
        return context.dataSources.postAPI.findAll();
      },
    },
  },
  formatError: (formattedError, originalError) => {
    // Both parameters are properly typed
    console.error('GraphQL Error:', {
      message: formattedError.message,
      path: formattedError.path,
      locations: formattedError.locations,
    });
    return formattedError;
  },
};

const server = new ApolloServer<MyContext>(config);

Working with GraphQL Requests and Responses

import type { 
  GraphQLRequest, 
  GraphQLResponse, 
  VariableValues 
} from "@apollo/server";

// Type-safe request handling
async function executeTypedOperation<TData, TVariables extends VariableValues>(
  server: ApolloServer<MyContext>,
  request: GraphQLRequest<TVariables>,
  contextValue: MyContext
): Promise<TData | null> {
  const response: GraphQLResponse<TData> = await server.executeOperation(
    request,
    { contextValue }
  );

  if (response.body.kind === 'single') {
    const result = response.body.singleResult;
    if (result.errors) {
      throw new Error(`GraphQL errors: ${result.errors.map(e => e.message).join(', ')}`);
    }
    return result.data || null;
  }
  
  throw new Error('Incremental delivery not supported in this context');
}

// Usage example
interface GetUserVariables {
  userId: string;
}

interface GetUserData {
  user: {
    id: string;
    email: string;
  } | null;
}

const userData = await executeTypedOperation<GetUserData, GetUserVariables>(
  server,
  {
    query: `
      query GetUser($userId: ID!) {
        user(id: $userId) {
          id
          email
        }
      }
    `,
    variables: { userId: '123' },
  },
  myContext
);

Custom Plugin with Type Safety

import type { 
  ApolloServerPlugin, 
  GraphQLRequestListener,
  GraphQLRequestContext 
} from "@apollo/server";

// Performance monitoring plugin
function createPerformancePlugin<TContext extends BaseContext>(): ApolloServerPlugin<TContext> {
  return {
    requestDidStart(): Promise<GraphQLRequestListener<TContext>> {
      let startTime: number;
      
      return Promise.resolve({
        didResolveOperation(requestContext: GraphQLRequestContext<TContext>) {
          startTime = Date.now();
          console.log(`Starting operation: ${requestContext.operationName || 'Anonymous'}`);
          return Promise.resolve();
        },
        
        willSendResponse(requestContext: GraphQLRequestContext<TContext>) {
          const duration = Date.now() - startTime;
          console.log(`Operation completed in ${duration}ms`);
          
          // Add performance headers
          requestContext.response?.http.headers.set('X-Response-Time', `${duration}ms`);
          return Promise.resolve();
        },
        
        didEncounterErrors(requestContext: GraphQLRequestContext<TContext>) {
          console.error(`Operation failed: ${requestContext.operationName}`, 
                       requestContext.errors?.map(e => e.message));
          return Promise.resolve();
        },
      });
    },
  };
}

// Use the plugin with type safety
const server = new ApolloServer<MyContext>({
  typeDefs,
  resolvers,
  plugins: [
    createPerformancePlugin<MyContext>(),
  ],
});

HTTP Integration Types

import type { 
  HTTPGraphQLRequest, 
  HTTPGraphQLResponse, 
  HeaderMap 
} from "@apollo/server";

// Custom HTTP handler
async function handleGraphQLRequest(
  server: ApolloServer<MyContext>,
  httpRequest: HTTPGraphQLRequest,
  createContext: () => Promise<MyContext>
): Promise<HTTPGraphQLResponse> {
  
  const httpGraphQLResponse = await server.executeHTTPGraphQLRequest({
    httpGraphQLRequest,
    context: createContext,
  });

  // Modify response headers
  httpGraphQLResponse.headers.set('X-Powered-By', 'Apollo Server');
  
  return httpGraphQLResponse;
}

// Working with HeaderMap
function processHeaders(headers: HeaderMap): void {
  // Case-insensitive access
  const contentType = headers.get('Content-Type');
  const authorization = headers.get('authorization');
  
  // Add custom headers
  headers.set('X-API-Version', '1.0');
  headers.set('Cache-Control', 'no-cache');
  
  // Iterate headers
  for (const [name, value] of headers) {
    console.log(`${name}: ${value}`);
  }
}