or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

error-handling.mdindex.mdplugins.mdserver-setup.mdtypes.md
tile.json

server-setup.mddocs/

Server Setup

Core ApolloServer class and configuration for creating GraphQL servers with batteries-included Express integration.

Capabilities

ApolloServerBase Class

Base server class providing core GraphQL functionality that all Apollo Server integrations extend.

/**
 * Base Apollo Server class with core GraphQL functionality
 * Extended by integration-specific server classes like ApolloServer
 */
class ApolloServerBase<ContextFunctionParams = any> {
  constructor(config: Config<ContextFunctionParams>);
  
  /**
   * Start the server - must be called before handling requests
   * Initializes schema, plugins, and prepares server for operation
   */
  start(): Promise<void>;
  
  /**
   * Stop the server and clean up resources
   * Calls serverWillStop on all plugins and cleans up connections
   */
  stop(): Promise<void>;
  
  /**
   * Execute a GraphQL operation directly (primarily for testing)
   * Bypasses HTTP layer and executes operation against schema
   * @param request - GraphQL request with query and variables
   * @param contextValue - Optional context for the operation
   * @returns Promise resolving to GraphQL response
   */
  executeOperation(
    request: Omit<GraphQLRequest, 'query'> & { query?: string | DocumentNode },
    contextValue?: ContextFunctionParams
  ): Promise<GraphQLResponse>;
  
  /**
   * Ensure server is started, throwing if not
   * Internal method used by other server methods
   */
  protected ensureStarted(): Promise<void>;
  
  /**
   * Get GraphQL options for request processing
   * Internal method for processing GraphQL requests
   */
  protected graphQLServerOptions(integrationContextArgument?: ContextFunctionParams): Promise<GraphQLServerOptions>;
}

Usage Examples:

import { ApolloServerBase } from 'apollo-server';

// Extend ApolloServerBase for custom integration
class CustomApolloServer extends ApolloServerBase {
  async start() {
    await super.start();
    console.log('Custom server started');
  }
  
  async handleRequest(request: any) {
    await this.ensureStarted();
    // Custom request handling logic
  }
}

// Testing with executeOperation
const server = new ApolloServerBase({
  typeDefs: gql`
    type Query {
      hello: String
    }
  `,
  resolvers: {
    Query: {
      hello: () => 'Hello world!',
    },
  },
});

await server.start();

// Execute operation for testing
const response = await server.executeOperation({
  query: 'query { hello }',
});

console.log(response.data); // { hello: 'Hello world!' }

await server.stop();

ApolloServer Class

Main server class that automatically creates Express app and HTTP server with GraphQL middleware.

/**
 * Main Apollo Server class with batteries-included Express setup
 * Extends ApolloServerExpress with automatic server creation
 */
class ApolloServer extends ApolloServerExpress {
  constructor(config: ApolloServerExpressConfig & {
    cors?: CorsOptions | boolean;
    onHealthCheck?: (req: express.Request) => Promise<any>;
    healthCheckPath?: string | null;
    stopGracePeriodMillis?: number;
  });
  
  /**
   * Start the server and begin listening for connections
   * @param opts - Options passed to http.Server.listen()
   * @returns Promise resolving to server information
   */
  listen(...opts: Array<any>): Promise<ServerInfo>;
  
  /**
   * Not supported - throws error directing to apollo-server-express
   */
  applyMiddleware(): never;
  
  /**
   * Not supported - throws error since listen() handles startup
   */
  start(): Promise<never>;
}

Usage Examples:

import { ApolloServer, gql } from 'apollo-server';

// Basic server setup
const server = new ApolloServer({
  typeDefs: gql`
    type Query {
      hello: String
    }
  `,
  resolvers: {
    Query: {
      hello: () => 'Hello world!',
    },
  },
});

// Start server on port 4000 (default)
server.listen().then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`);
});

// Start server on specific port
server.listen({ port: 8080 }).then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`);
});

// Advanced configuration
const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: ({ req }) => ({
    user: getUser(req.headers.authorization),
  }),
  cors: {
    origin: ['https://mydomain.com', 'https://anotherdomain.com'],
    credentials: true,
  },
  onHealthCheck: async (req) => {
    // Custom health check logic
    return new Promise((resolve) => {
      // Check database connectivity, etc.
      resolve('OK');
    });
  },
  healthCheckPath: '/health',
  stopGracePeriodMillis: 10000,
  plugins: [
    // Add custom plugins
  ],
});

ServerInfo Interface

Information returned when the server starts listening.

/**
 * Server information returned from listen() method
 */
interface ServerInfo {
  /** Server address (e.g., '127.0.0.1' or '::1') */
  address: string;
  /** Address family ('IPv4' or 'IPv6') */
  family: string;
  /** Complete server URL including protocol and port */
  url: string;
  /** Port number the server is listening on */
  port: number | string;
  /** Underlying HTTP server instance */
  server: http.Server;
}

Configuration Interface

Core configuration interface extending Express-specific options.

/**
 * Configuration options for ApolloServer
 * Extends ApolloServerExpressConfig with additional options
 */
interface ApolloServerConfig extends ApolloServerExpressConfig {
  /** CORS configuration - can be boolean or detailed options */
  cors?: CorsOptions | boolean;
  
  /** Custom health check function */
  onHealthCheck?: (req: express.Request) => Promise<any>;
  
  /** Custom health check endpoint path (null to disable) */
  healthCheckPath?: string | null;
  
  /** Grace period in milliseconds for graceful shutdown */
  stopGracePeriodMillis?: number;
}

/**
 * Base configuration interface from apollo-server-core
 */
interface Config {
  /** GraphQL type definitions */
  typeDefs?: TypeSource;
  
  /** GraphQL field resolvers */
  resolvers?: IResolvers | Array<IResolvers>;
  
  /** GraphQL schema instance (alternative to typeDefs + resolvers) */
  schema?: GraphQLSchema;
  
  /** Context object or function for request context */
  context?: Context<ContextFunctionParams> | ContextFunction<ContextFunctionParams, any>;
  
  /** Array of plugins to extend server functionality */
  plugins?: PluginDefinition[];
  
  /** Enable GraphQL introspection (defaults to NODE_ENV !== 'production') */
  introspection?: boolean;
  
  /** Enable debug mode with additional logging */
  debug?: boolean;
  
  /** Custom validation rules */
  validationRules?: ValidationRule[];
  
  /** Custom executor function */
  executor?: GraphQLExecutor;
  
  /** Format response function */
  formatResponse?: (response: GraphQLResponse, requestContext: GraphQLRequestContext) => GraphQLResponse;
  
  /** Format error function */
  formatError?: (error: GraphQLError) => GraphQLFormattedError;
  
  /** Apollo Studio configuration */
  apollo?: ApolloConfigInput;
  
  /** Cache implementation */
  cache?: KeyValueCache;
  
  /** Custom schema hash for Apollo Studio */
  schemaHash?: string;
  
  /** Document store for persisted queries */
  documentStore?: DocumentStore;
  
  /** Parse options for GraphQL documents */
  parseOptions?: ParseOptions;
}

CORS Configuration

CORS options for cross-origin request handling.

/**
 * CORS configuration options (from cors package)
 */
interface CorsOptions {
  /** Allowed origins - can be string, array, function, or boolean */
  origin?: boolean | string | RegExp | Array<string | RegExp> | ((origin: string, callback: (err: Error | null, allow?: boolean) => void) => void);
  
  /** Allowed HTTP methods */
  methods?: string | string[];
  
  /** Allowed headers */
  allowedHeaders?: string | string[];
  
  /** Exposed headers */
  exposedHeaders?: string | string[];
  
  /** Enable credentials */
  credentials?: boolean;
  
  /** Max age for preflight cache */
  maxAge?: number;
  
  /** Enable preflight continue */
  preflightContinue?: boolean;
  
  /** Status code for successful OPTIONS requests */
  optionsSuccessStatus?: number;
}

Context Management

Context types for request-scoped data and authentication.

/**
 * Base context type
 */
interface BaseContext {
  [key: string]: any;
}

/**
 * Context function type for dynamic context creation
 */
type ContextFunction<FunctionParams, ProducedContext> = (
  params: FunctionParams
) => Promise<ProducedContext> | ProducedContext;

/**
 * Express-specific context parameters
 */
interface ExpressContext {
  req: express.Request;
  res: express.Response;
}

Context Usage Examples:

// Static context
const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: {
    dataSources: {
      userAPI: new UserAPI(),
      postAPI: new PostAPI(),
    },
  },
});

// Dynamic context with authentication
const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: async ({ req }) => {
    // Get user from token
    const token = req.headers.authorization || '';
    const user = await getUser(token);
    
    return {
      user,
      dataSources: {
        userAPI: new UserAPI(),
        postAPI: new PostAPI(),
      },
    };
  },
});

Server Lifecycle

Understanding the server startup and shutdown process.

Startup Process:

  1. Constructor validates configuration and sets up plugins
  2. listen() calls internal _start() to initialize server
  3. Express app is created and middleware is applied
  4. HTTP server starts listening on specified port
  5. Promise resolves with ServerInfo

Shutdown Process:

  1. Server receives shutdown signal
  2. stopGracePeriodMillis determines grace period
  3. HTTP server stops accepting new connections
  4. Existing connections are allowed to complete
  5. Server shuts down gracefully
// Graceful shutdown example
const server = new ApolloServer({
  typeDefs,
  resolvers,
  stopGracePeriodMillis: 10000, // 10 seconds
});

const { server: httpServer } = await server.listen({ port: 4000 });

// Handle shutdown signals
process.on('SIGTERM', () => {
  console.log('SIGTERM received, shutting down gracefully');
  httpServer.close(() => {
    console.log('Server closed');
  });
});

DataSource Integration

Base class for creating data sources that provide data fetching and caching capabilities.

/**
 * Base class for data sources
 * Provides initialization lifecycle and type safety
 */
abstract class DataSource<TContext = any> {
  /**
   * Initialize the data source with context and cache
   * Called when the server starts up
   * @param config - Configuration containing context and cache instances
   */
  initialize?(config: DataSourceConfig<TContext>): void | Promise<void>;
}

/**
 * Configuration passed to data source during initialization
 */
interface DataSourceConfig<TContext> {
  /** Request context object */
  context: TContext;
  
  /** Cache instance for data source operations */
  cache: KeyValueCache;
}

/**
 * Data sources configuration for server
 */
type DataSources<TContext = BaseContext> = {
  [name: string]: DataSource<TContext>;
};

DataSource Usage Examples:

import { DataSource } from 'apollo-server';

// Custom data source implementation
class UserAPI extends DataSource {
  private baseURL = 'https://api.example.com';
  
  async initialize(config) {
    // Access context and cache during initialization
    this.context = config.context;
    this.cache = config.cache;
  }
  
  async getUser(id: string) {
    const cacheKey = `user:${id}`;
    const cached = await this.cache.get(cacheKey);
    
    if (cached) {
      return JSON.parse(cached);
    }
    
    const user = await fetch(`${this.baseURL}/users/${id}`).then(r => r.json());
    await this.cache.set(cacheKey, JSON.stringify(user), { ttl: 300 });
    
    return user;
  }
}

// Configure data sources in server
const server = new ApolloServer({
  typeDefs,
  resolvers,
  dataSources: () => ({
    userAPI: new UserAPI(),
    postAPI: new PostAPI(),
  }),
  context: ({ req }) => ({
    user: getUser(req.headers.authorization),
  }),
});

// Use data sources in resolvers
const resolvers = {
  Query: {
    user: (parent, { id }, { dataSources }) => {
      return dataSources.userAPI.getUser(id);
    },
  },
};