Essential type definitions for server configuration, request/response handling, context management, and plugin development in Apollo Server.
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;
}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;
}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> };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;
}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;
}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>);
}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;
}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);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
);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>(),
],
});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}`);
}
}